Fallback chain
A Llm can carry an ordered list of other
configuration identifiers to fall back to on retryable provider
failures. The lookup happens transparently inside
Netresearch
and complete. Callers see a regular
completion response or a typed exception; they never need to
reach into retry mechanics.
Configuring a chain
The tx_ column stores a
JSON object with a single key, configurationIdentifiers, whose
value is the ordered array of target configuration identifiers:
fallback_chain
{"configurationIdentifiers": ["claude-sonnet", "ollama-local"]}
Editors paste that JSON into the Fallback Chain tab in
the backend form. The order is the retry order. Identifiers are
matched case-insensitively against tx_.
Using an object (rather than a bare top-level array) leaves room for
future sibling fields — e.g. per-link retry policy — without a
schema break.
Retryable vs. non-retryable errors
Fallback only triggers for errors the next provider might actually recover from:
| Exception | Retryable? |
|---|---|
Provider (network, timeout,
HTTP 5xx, retries exhausted) | Yes |
Provider with code 429
(rate-limited by this provider) | Yes |
Provider with any other 4xx
(authentication, bad request, not found, …) | No. Bubbles up. A different provider with the same input would fail the same way. |
Provider | No. Misconfiguration is a human problem. |
Unsupported | No. Fallback won't make a text-only provider handle images. |
When every configuration in the chain trips a retryable error,
Netresearch
is thrown. It carries the per-attempt errors so consumers can
surface the full failure sequence.
Scope limits
v1 is deliberately narrow:
- No streaming.
streamdoes not wrap the call. Once the first chunk has been yielded to the caller, mid-stream provider-switching would be detectable and surprising.Chat With Configuration () - No recursion. A fallback configuration's own chain is
ignored. This avoids cycles (
a -> b -> a) and unbounded attempt trees. - Single primary-only chain is a no-op. If the configured
chain contains only the primary's own identifier, the primary's
original exception is rethrown verbatim rather than wrapped in
Fallback.Chain Exhausted Exception
Using the DTO directly
For programmatic construction — e.g. a wizard that generates a
configuration and also sets up fallback — use the
Netresearch value object:
use Netresearch\NrLlm\Domain\DTO\FallbackChain;
$chain = (new FallbackChain())
->withLink('claude-sonnet')
->withLink('ollama-local');
$configuration->setFallbackChainDTO($chain);
The DTO trims and lowercases identifiers on entry, deduplicates them, and silently rejects empty strings and non-string entries read from malformed JSON. See ADR-021: Provider Fallback Chain for the full design rationale and the alternatives we ruled out.