Skip to content

EU data residency

Definition

EU data residency is the guarantee that a gateway processes model data only inside the European Union. A gateway that is put into EU-region routing mode serves a request only when the resolved provider and region are EU-hosted; any other route is refused.

Function

EU-region routing exists for deployments where model data must stay in the EU, such as regulated and public-sector tenants. When the residency floor is armed, the gateway fails closed: a request whose provider or region is not EU-hosted is rejected with HTTP 403 (data_residency_blocked) before any upstream call, so the request never reaches a non-EU endpoint.

The floor is off by default. It is armed per gateway (eu_region_routing), armed organisation-wide from Settings → Organisation → Routing (a floor no gateway can go below), or set deployment-wide on a sovereign stack.

Rules and facts

  • Every dispatch path is covered. The check sits at the single upstream dispatch point, so the same refusal applies to the primary request, every failover attempt, each tool-loop leg, and the agentic-fetch call. The conversation-summary (compaction) call is the one exception to "single point": it dispatches on its own, and reaches the same verdict by calling the same shared gate rather than by passing through that point. One consequence is worth knowing: the observed-host re-check described below lives at the dispatch point, so it does not apply to the compaction call — a compaction routed to myra is checked before dispatch but not re-checked against the host that actually served it.
  • The observed upstream host is re-checked, not just the picked provider. The self-hosted EU fleet (provider myra) is fronted by a router that can transparently overflow a saturated in-house model group to a cloud fallback (for example a US endpoint). That overflow is invisible to the pre-dispatch provider check, which vouches myra as EU. After a successful response, the gateway therefore re-evaluates the host the request was actually served from (reported by the upstream): on an armed gateway a non-EU observed host is refused with the same 403 data_residency_blocked before any answer bytes reach the client. Because this specific overflow is a TRANSIENT in-house capacity condition (not a static misconfiguration), the gateway retries the same route a bounded number of times (the gateway's normal retry_count, with backoff between attempts) before failing over to the next EU route or, absent one, surfacing the 403 — a static pre-dispatch refusal (a genuinely non-EU/non-allowlisted provider) is never retried, only this post-hoc overflow case. This retry never counts against the shared myra health/circuit-breaker signal: myra itself answered successfully, it only routed off-EU for this residency-armed gateway, so a saturation window on one such gateway cannot trip the (fleet-wide, cross-tenant) breaker for every other gateway on the myra fleet. The observed host is untrusted upstream data — a host that cannot be positively vouched as EU is treated as non-EU (fail closed). The positive-EU host set defaults to the Myra fleet domain and is configurable per deployment by your operator (a list of DNS suffixes; private/loopback IPs are always treated as EU).
  • Operational requirement (armed gateways). Because the observed-host check fails closed, an EU upstream node on an armed gateway MUST be reported by the router under a recognized EU DNS suffix (the default .myra.eu, or a suffix your operator adds to the deployment's positive-EU host set). A legit EU node addressed by a bare public IP or an unlisted internal hostname classifies as unvouchable and is refused — your operator must add its suffix to that set. This trade-off is deliberate: an unrecognized host is never silently trusted. A refused observed host is logged ([residency_egress_block]) so a misconfiguration is distinguishable from a genuine overflow.
  • Web search is forced through the EU path. Under the floor, a non-EU search backend is blocked and provider-native search is routed through the gateway EU two-leg. An armed gateway can turn web search off, but never falls back to a non-EU search backend.
  • Model-slug search is guaranteed off only under the armed floor. Web search that is intrinsic to a model name (for example OpenAI gpt-*-search-preview, Groq compound, Perplexity sonar) runs on the model's own server regardless of any request knob, so the gateway cannot strip it. Under the armed floor this is a non-issue — such a model is a non-EU provider and is dispatch-blocked before it runs. But a gateway that only configures an EU search provider (web_search.provider: "linkup") without arming eu_region_routing does not dispatch-block the model, so a gpt-*-search-preview request still reaches its US backend for the whole request. Pair the EU search provider with the armed residency floor for full sovereignty; configuring linkup alone is not sufficient. See Web search — EU data residency.
  • Per-tenant region selection. A tenant carries a default EU region for AWS Bedrock and Google Vertex, inherited by every gateway under it that sets no region of its own. Regions are validated as EU-member regions at the trust boundary, independent of whether enforcement is on.
  • Embeddings and image generation are served only by the on-premise Myra EU fleet.

Residency evidence (per-request jurisdiction)

Independently of whether the floor is armed, every model dispatch records the jurisdiction it actually ran in, as immutable evidence for data-localization reporting. Each request-log leg carries a residency zone, resolved and frozen at dispatch time:

  • eu — the model dispatch was positively EU-vouched (identical to the fail-closed dispatch guarantee: an EU provider, or an EU Bedrock/Vertex/Azure region, with a Bedrock model pinned to a single EU-27 region). When the upstream reports the host it actually served from, the recorded zone reflects that observed host — so a request the picked EU provider transparently overflowed to a non-EU cloud fallback is recorded as non_eu (or unknown), never laundered to eu. This honesty applies on every gateway, including one that does not arm the residency floor, so the compliance export always reflects the real egress.
  • non_eu — a positively known non-EU host (a US provider or SaaS, DeepSeek in China, a US Bedrock/Vertex region, or an Azure non-EU region). non_eu spans the US and China; the per-provider breakdown remains available.
  • unknown — the jurisdiction cannot be proven at dispatch: opaque or variable routing (OpenRouter), a Bedrock cross-region inference profile that cannot be proven to stay within the EU-27, a per-gateway base-URL override to an unvouchable host, an Azure route with no region asserted, or a region-configurable/self-hosted provider (Hugging Face, custom). unknown is counted as not EU-clean in the report, so it never under-states egress.
  • empty — the leg was not a residency-bearing leg (a guardrail or PII leg), or the request was residency-blocked before any dispatch. Such requests are neither EU-clean nor non-EU.

The zone is frozen at dispatch and never recomputed from the current gateway configuration — unlike the model hosting label, which is a mutable display value. It is server-authoritative: a client cannot influence the zone recorded for its own request.

Search-egress jurisdiction (second axis)

The model-generated web-search query egresses to a separate backend on its own jurisdiction axis. Every gateway-path web-search egress now records its own residency-zoned leg (kind = web_search_query), zoned by the search provider rather than the model:

  • eu — an EU-vouched search backend (linkup, France; SOC 2 II, Art. 28 DPA, zero-retention).
  • non_eu — any other search backend, including the historical Brave (US) default and any unrecognized provider (fail-closed).

The zone is recorded on every egress attempt — a search whose queries all failed still egressed the query text to the backend, so it still leaves an evidence leg (only a fully withheld/residency-blocked search, where nothing left the gateway, records nothing). This is orthogonal to billing: Brave stays unmetered as before; the leg is evidence, not a charge.

Under the EU floor, web search is forced through the gateway EU two-leg (linkup), so on an armed gateway the search axis is always eu. On a non-enforced gateway a model may instead run its own provider-native web search — Anthropic web_search, Gemini/Vertex googleSearch grounding, the OpenRouter web plugin, or the Mistral Agents web_search tool. Each of these now records its own kind = web_search_query residency leg, zoned by the native backend, so that egress is no longer invisible:

  • non_eu — every provider-native backend today (none is EU-vouched: Anthropic and Gemini/Vertex search on US infrastructure, OpenRouter's plugin falls back to a US provider, and Mistral's Agents web_search uses a non-EU search subprocessor).

The native-search leg is captured from the final outbound request, so it covers both search the gateway enabled from a request header/config and a native search directive a client supplied directly (a raw Anthropic web_search tool, an OpenRouter plugins:[{id:"web"}] or :online model slug, a Gemini web_search marker). It is evidence only — never billed and never counted in the model token totals.

Mistral is two axes at once, deliberately kept apart. A Mistral request that uses native web search records a model leg zoned eu (the model ran on Mistral's EU host) and a separate web_search_query leg zoned non_eu (its search subprocessor is not EU-vouched). The two are never merged: the model-host zone stays truthful, and the search-egress zone still marks the request as not EU-clean.

💡 Note: The full, current list of subprocessors — including the search and model backends named above and where they process data — is published in Myra's public Trust Center at /trust, with a downloadable subprocessor register. See Subprocessors.

One documented residual remains: OpenAI model-slug search (web_search_options / gpt-*-search-preview), where the search is intrinsic to the model name and cannot be detected as a distinct request-side directive. It is guaranteed off only under the armed floor (the model is a non-EU provider and is dispatch-blocked); on a non-enforced gateway it is not captured as a distinct leg.

The per-request verdict folds a request's residency-bearing legs worst-case: any non_eu or unknown leg (model or search) makes the whole request not EU-clean.