Summary
The api-proxy sidecar's apiProxy.modelFallback config defaults to {enabled: true, strategy: middle_power}. When Copilot CLI sends a model that is not present in the cached provider catalog, the proxy rewrites the request body's model field to a family-matched median-power catalog model. For BYOK Azure OpenAI deployments — where COPILOT_MODEL is the user-defined deployment name rather than the upstream catalog name — this rewrite causes Azure to reject the request with HTTP 404 DeploymentNotFound. This is the 404 symptom reported in gh-aw #35483.
Root cause
containers/api-proxy/model-resolver.js runs tryMiddlePowerFallback for any model not found in the cached catalog.
- Default config (from
src/awf-config-schema.json ~L163–182, applied by buildApiProxyService() in src/services/api-proxy-service.ts ~L86–170):
{ "apiProxy": { "modelFallback": { "enabled": true, "strategy": "middle_power" } } }
- For non-
githubcopilot BYOK targets (Azure OpenAI, custom OpenAI-compatible), the deployment name is opaque to the proxy — no remote catalog exists to reconcile against. The proxy still applies middle_power and replaces the user-specified deployment name with a base-catalog name (e.g. gpt-5-mini-zarenner-test → gpt-5-mini-2025-08-07).
Reproduction
- Configure a Copilot BYOK workflow against Azure OpenAI with a deployment name that differs from the catalog name, e.g.
gpt-5-mini-zarenner-test (Azure deployment of base gpt-5-mini-2025-08-07):
engine:
id: copilot
env:
COPILOT_PROVIDER_BASE_URL: "https://<resource>.openai.azure.com/openai/v1"
COPILOT_MODEL: gpt-5-mini-zarenner-test
COPILOT_PROVIDER_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
- With companion gh-aw auth workarounds applied (see gh-aw #35483 and sibling gh-aw issues), so the request actually reaches Azure, observe HTTP 404:
{"error":{"code":"DeploymentNotFound","message":"The API deployment for this resource does not exist..."}}
- Inspect
awf-reflect.json from the audit logs: model_fallback.enabled: true.
- Direct
curl to Azure with the deployment name returns HTTP 200 — proving it is the proxy rewrite, not Azure or the request shape, that produces the 404.
Workaround
Set apiProxy.modelFallback.enabled: false in awf-config.json. This isn't currently exposed by gh-aw's compiler (filed separately on the gh-aw side), so a post-compile sed against the lock file is required today:
sed -i.bak \
's|"apiProxy":{"enabled":true,|"apiProxy":{"enabled":true,"modelFallback":{"enabled":false,"strategy":"middle_power"},|' \
.github/workflows/<name>.lock.yml
Verified by re-running and confirming awf-reflect.json now shows model_fallback.enabled: false and api-proxy otel logs show status 200. The agent successfully completed an Azure OpenAI BYOK round-trip with this patch.
Proposed fixes (options)
- Default
enabled: false for non-githubcopilot BYOK targets. When the resolved upstream hostname is not the official Copilot API, middle_power rewriting is almost always wrong because no shared catalog exists. (Minimal-impact option.)
- Default
enabled: false globally and require explicit opt-in. The feature is useful for the official Copilot catalog but a silent-failure footgun on any custom provider.
- Strict pass-through heuristic: when
model is missing from the cached catalog and the target is a custom provider, pass the model name through unchanged rather than rewriting.
Context
Summary
The api-proxy sidecar's
apiProxy.modelFallbackconfig defaults to{enabled: true, strategy: middle_power}. When Copilot CLI sends amodelthat is not present in the cached provider catalog, the proxy rewrites the request body'smodelfield to a family-matched median-power catalog model. For BYOK Azure OpenAI deployments — whereCOPILOT_MODELis the user-defined deployment name rather than the upstream catalog name — this rewrite causes Azure to reject the request with HTTP 404DeploymentNotFound. This is the 404 symptom reported in gh-aw #35483.Root cause
containers/api-proxy/model-resolver.jsrunstryMiddlePowerFallbackfor any model not found in the cached catalog.src/awf-config-schema.json~L163–182, applied bybuildApiProxyService()insrc/services/api-proxy-service.ts~L86–170):{ "apiProxy": { "modelFallback": { "enabled": true, "strategy": "middle_power" } } }githubcopilotBYOK targets (Azure OpenAI, custom OpenAI-compatible), the deployment name is opaque to the proxy — no remote catalog exists to reconcile against. The proxy still appliesmiddle_powerand replaces the user-specified deployment name with a base-catalog name (e.g.gpt-5-mini-zarenner-test→gpt-5-mini-2025-08-07).Reproduction
gpt-5-mini-zarenner-test(Azure deployment of basegpt-5-mini-2025-08-07):{"error":{"code":"DeploymentNotFound","message":"The API deployment for this resource does not exist..."}}awf-reflect.jsonfrom the audit logs:model_fallback.enabled: true.curlto Azure with the deployment name returns HTTP 200 — proving it is the proxy rewrite, not Azure or the request shape, that produces the 404.Workaround
Set
apiProxy.modelFallback.enabled: falseinawf-config.json. This isn't currently exposed by gh-aw's compiler (filed separately on the gh-aw side), so a post-compile sed against the lock file is required today:Verified by re-running and confirming
awf-reflect.jsonnow showsmodel_fallback.enabled: falseand api-proxy otel logs show status200. The agent successfully completed an Azure OpenAI BYOK round-trip with this patch.Proposed fixes (options)
enabled: falsefor non-githubcopilotBYOK targets. When the resolved upstream hostname is not the official Copilot API,middle_powerrewriting is almost always wrong because no shared catalog exists. (Minimal-impact option.)enabled: falseglobally and require explicit opt-in. The feature is useful for the official Copilot catalog but a silent-failure footgun on any custom provider.modelis missing from the cached catalog and the target is a custom provider, pass the model name through unchanged rather than rewriting.Context
v0.76.1, gh-aw-firewallv0.25.55, Copilot CLIv1.0.52apiProxy.modelFallbackdefault added in PRs feat(api-proxy): middle-power model fallback when selection criteria fail #3606, feat(api-proxy): add middle-power model fallback with stale-cache recovery #3607