Fallbacks and Providers
Fallback chains, provider ranking, allow and deny lists -- what the gateway expresses to the upstream, and what it refuses to serve without.
Fallbacks and Providers
Two different things live on a routing profile and are easy to confuse.
A fallback chain is about models: which other model may answer when the decided one cannot be served. Provider preferences are about endpoints: which provider, among those that serve the decided model, should get the request.
Fallback chains
An ordered list of alternative models, at most 4 beyond the primary, tried first entry first.
The gateway does not walk the chain itself. It expresses the chain to the upstream, and the upstream performs the failover. What the gateway records is what actually served.
And a chain is not a retry: a retry re-sends the same request to the same model, where a chain moves to a different model.
Two rules keep a chain honest:
- Every model in the chain passes the same governance gate as the decided model. Entries your guardrail forbids are dropped before the request is forwarded, so nothing a rule denies can serve by way of a fallback.
- A resolved empty chain means no chain -- never "try anything".
A chain is the one configured path that can legitimately make the served model differ from the decided one, and when it fires, the turn is recorded as a representation break: the session's routing pin moves where one exists, and that turn is denied the cross-turn cache discount, because the newly-serving model's prompt cache is cold however identical the bytes are.
Provider preferences
Four independent fields, each merged separately down the ladder.
| Field | Effect |
|---|---|
| Rank providers by | cost, latency or throughput. |
| Preferred providers | An explicit order, tried before any other eligible endpoint. |
| Allowed providers | Only these may serve. Blank means no restriction. |
| Denied providers | These never serve. |
Allow and deny are separate fields rather than one signed list, because a team that allows three providers and a team that denies three are making different, non-substitutable statements.
These are written in DevZero's own vocabulary and translated onto whatever knobs the upstream exposes, inside the connector. No upstream concept reaches the profile schema or the API -- and the upstream's raw routing shapes are refused if you send them in a request body.
An entry may narrow to one of a provider's serving variants by naming its endpoint tag, which the catalog shows per endpoint.
Matching is case-insensitive and by whole slug. Wildcard patterns you write in a guardrail are expanded into literal slugs when the authorization decision is issued, so the request-time test is a set test rather than a pattern test -- a rule a caller could satisfy by writing their own pattern is a rule that does not bind.
Preference degrades, restriction refuses
Not every upstream can express everything, and the gateway's response depends on what would be lost.
| What cannot be expressed | Outcome |
|---|---|
| A ranking, or a preferred order | Degrades. The request proceeds, and the loss is recorded on the row so "this request lost something" is a positive value rather than an absence. |
| A fallback chain | Degrades, recorded the same way. |
| An allow or deny list | Refused. Serving would route to a provider somebody forbade -- and the somebody may be your team's policy rather than the caller. |
| A content guardrail | Refused, with an extra reason: a filter that does not run leaves no trace at all. The request would succeed with unfiltered content and an entirely ordinary-looking response. |
| Auto mode | Refused, structurally: a delegated decision carries no model to fall back to. |
That check runs once, before translation and outside the connector. A connector asked to police its own decision can forget to, and silent truncation is the failure this removes.
The refusal bounds where traffic goes, not what you can receive. It runs at translation, and the caches run before it -- so a request whose restriction an upstream cannot express can still be answered from a cache entry, because a cache hit contacts no provider at all.
Direct providers behave differently, and they have to
On an upstream that serves exactly one provider, a ranking has nothing to rank:
| Field | On a marketplace upstream | On a direct provider upstream |
|---|---|---|
| Ranking | Expressed, or degraded | Inert. Nothing was under-delivered, so nothing is recorded. |
| Allow / deny | Expressed, or refused | Decidable locally. Satisfied when it permits the provider, refused when it excludes it. |
Without that split, a team guardrail's provider list unioned into every decision would lock every governed team out of a direct upstream entirely.
The one default you do not have to configure
An anthropic/* decision that no rung gave a provider order is sent asking for
the Anthropic first-party endpoint first.
Claude's automatic prompt-cache breakpoints are guaranteed only there. A request served by a resale endpoint loses them with no error and no visible difference in the reply -- only in the bill.
It is a default, so it stands down the moment you express a preference of your own: an explicit order, a non-empty allow list, or a deny naming the same provider.
What gets recorded
| Field | Answers |
|---|---|
served_model | Which model actually answered. |
served_provider | Which provider behind the upstream answered. |
routing_switch_reason | Why the served model differs from the decided one. |
routing_degraded | What could not be expressed and was proceeded without. |
If you configure preferences, read those columns. The gateway passes a preference on; it does not promise the upstream honoured it, and this is where you find out.