cloudflare / cloudflare/workers-sdk

Cloudflare-Workers-Version-Overrides is ignored on fetch Service Binding when targeting a 0% version in the current deployment

Open
#15,536 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
186

Description

# Cloudflare-Workers-Version-Overrides is ignored on fetch Service Binding when targeting a 0% version in the current deployment

## Summary

A production-deployed caller Worker made a `fetch()`-based Service Binding subrequest to a downstream Worker whose current deployment contained two versions: version A at 100% traffic and version B at 0% traffic. Setting `Cloudflare-Workers-Version-Overrides` to version B did not change the downstream behavior. Both the no-override and override requests executed version A behavior.

Classification: `PRODUCTION_SERVICE_BINDING_OVERRIDE_NOT_APPLIED`.

## Documented expectation

The current [Cloudflare Workers version overrides documentation](https://developers.cloudflare.com/workers/versions-and-deployments/version-overrides/) states that an override can target a version in the current deployment, including a version serving 0% of traffic. It also states that `Cloudflare-Workers-Version-Overrides` can be set on a `fetch()`-based Service Binding subrequest, in which case the downstream Worker should execute the specified version.

## Environment

- Wrangler `4.129.0`
- Module Workers
- Compatibility date: `2026-09-04`
- Caller and downstream Worker in the same Cloudflare account
- Downstream active deployment contained exactly two versions:
- version A: 100% traffic
- version B: 0% traffic
- The target version B was part of the **current deployment**, not merely an uploaded preview version.
- Service Binding used `fetch()`, not RPC.
- No custom domain was required.

## Minimal reproduction shape

Use two Workers:

`downstream-worker`

- Version A exposes exactly three observable MCP tools.
- Version B exposes exactly four observable MCP tools.
- Its active deployment is A = 100% and B = 0%.

`caller-worker`

- Has exactly one Service Binding: `DOWNSTREAM` to `downstream-worker`.
- Builds the same outgoing request in both tests.
- Test A sends no version override.
- Test B adds only the version-override header.

```ts
const headers = new Headers(baseHeaders);

if (useOverride) {
headers.set(
"Cloudflare-Workers-Version-Overrides",
'downstream-worker=""',
);
}

return env.DOWNSTREAM.fetch(
new Request("https://downstream.example/mcp", {
method: request.method,
headers,
body,
}),
);
```

The reproduction also set an explicit canonical `Host` header derived from the downstream request URL because the downstream MCP handler validates `Host`. That resolved an earlier authenticated `403` and is separate from the version-override result: both Test A and Test B used the same canonical Host header.

## Observed production result

The caller was deployed as a normal Worker with a temporary `workers.dev` endpoint. It was not run with `wrangler dev --remote`, edge preview, or a temporary-deployment command.

Before authentication, the caller-to-downstream path returned the expected `401` with the downstream OAuth challenge. Canonical OAuth authorization, callback, and allowlist validation then passed.

### Test A — no override

- Authenticated downstream MCP initialization: PASS
- Observed version A behavior
- Exactly three tools: `render_bridge_canary`, `canary_ping`, `model_pipeline_probe`

### Test B — override targeting version B

- Authenticated downstream MCP initialization: PASS
- Still observed version A behavior
- Exactly the same three tools: `render_bridge_canary`, `canary_ping`, `model_pipeline_probe`
- No error indicated that the override header was malformed.
- The candidate version remained at 0% in the downstream current deployment.

The same `OVERRIDE_NOT_APPLIED` behavior was observed earlier from `wrangler dev --remote` / edge preview. The important result here is that the behavior also reproduces from a normally deployed production-runtime caller.

## Safety and control evidence

- Version B was confirmed to be in the downstream current deployment at 0%.
- Baseline and override requests used the same Service Binding, canonical request URL, canonical Host header, authenticated request path, and MCP verifier.
- Authenticated initialization succeeded in both tests.
- The only semantic request difference was `Cloudflare-Workers-Version-Overrides`.
- Downstream application state was unchanged during the reproduction.
- The disposable production caller was deleted immediately after testing.

## Expected result

Test B should execute version B and expose four-tool behavior.

## Actual result

Test B executed the same 100%-traffic version A behavior as Test A and exposed the same three tools.

## Related context

This may relate to [cloudflare/workers-sdk#9342](https://github.com/cloudflare/workers-sdk/issues/9342). This reproduction is narrower: it concerns the currently documented ability to override a version that is already in the active deployment at 0%, not arbitrary uploaded preview versions.

## Questions for Cloudflare

1. Is fetch-based Service Binding version override currently supported in production for a target version at 0%?
2. If yes, is this a platform bug?
3. Is there an undocumented restriction involving `workers.dev`, OAuth-protected downstream Workers, or manually constructed `Request` objects?
4. Is there a supported way to observe whether the routing layer accepted or rejected a version override?

Contributor guide

Open the contributing guide

Research direction

The issue names no repository file or test; start by reading the linked version-overrides documentation and locating the production fetch-based Service Binding and version-override handling in workers-sdk. Reproduce the two-version deployment with the supplied caller and downstream Worker shape. Done means a 0% version in the current deployment is selected by the override, while the no-override request still uses the 100% version.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend, cloud
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.