{"record":{"id":"e4d616041a3193aa","repo":"bytedance/deer-flow","slug":"cannot-set-header-k-to-masked-value-pro","errorCode":null,"errorMessage":"Cannot set header '{k}' to masked value '***'; provide a real value.","messagePattern":"Cannot set header '(.+?)' to masked value '\\*\\*\\*'; provide a real value\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/app/gateway/routers/mcp.py","lineNumber":693,"sourceCode":"    for k, v in incoming.env.items():\n        if v == _MASKED_VALUE:\n            if k in existing.env:\n                merged_env[k] = existing.env[k]\n            else:\n                raise HTTPException(\n                    status_code=400,\n                    detail=f\"Cannot set env key '{k}' to masked value '***'; provide a real value.\",\n                )\n        else:\n            merged_env[k] = v\n\n    merged_headers = {}\n    for k, v in incoming.headers.items():\n        if v == _MASKED_VALUE:\n            if k in existing.headers:\n                merged_headers[k] = existing.headers[k]\n            else:\n                raise HTTPException(\n                    status_code=400,\n                    detail=f\"Cannot set header '{k}' to masked value '***'; provide a real value.\",\n                )\n        else:\n            merged_headers[k] = v\n\n    merged_oauth = incoming.oauth\n    if incoming.oauth is not None and existing.oauth is not None:\n        # None = preserve (masked round-trip), \"\" = explicitly clear, else = new value\n        merged_client_secret = existing.oauth.client_secret if incoming.oauth.client_secret is None else (None if incoming.oauth.client_secret == \"\" else incoming.oauth.client_secret)\n        merged_refresh_token = existing.oauth.refresh_token if incoming.oauth.refresh_token is None else (None if incoming.oauth.refresh_token == \"\" else incoming.oauth.refresh_token)\n        merged_oauth = incoming.oauth.model_copy(\n            update={\n                \"client_secret\": merged_client_secret,\n                \"refresh_token\": merged_refresh_token,\n            }\n        )\n    update = {","sourceCodeStart":675,"sourceCodeEnd":711,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/mcp.py#L675-L711","documentation":"400 raised under the same masked-value merge logic as env keys, but for HTTP headers: an update sends '***' for a header name that has no stored value on the existing server. Existing masked headers round-trip (stored value preserved); new masked headers cannot.","triggerScenarios":"PUT to /api/mcp/config with headers: {\"Authorization\": \"***\"} on a server that never had an Authorization header; adding a new header while copying masked values from a GET response.","commonSituations":"Adding auth headers to a previously anonymous HTTP/SSE MCP server via a masked round-trip payload; UI forms pre-filling '***' into new header inputs.","solutions":["Send the actual header value (e.g. the real bearer token) for new header keys","Reserve '***' strictly for keys already present in the stored config","Keep the source of truth for secrets in a vault and inject real values at submit time"],"exampleFix":"# before\nheaders: {\"X-Api-Key\": \"***\"}  # new header -> 400\n# after\nheaders: {\"X-Api-Key\": \"actual-key\"}","handlingStrategy":"validation","validationCode":"function resolveMaskedHeaders(incoming: Record<string, string>, existing: Record<string, string> | undefined): Record<string, string> { const out: Record<string, string> = {}; for (const [k, v] of Object.entries(incoming)) { if (v === '***') { if (!existing || !(k in existing)) throw new Error(`new header '${k}' needs a real value, not the mask`); out[k] = existing[k]; } else out[k] = v; } return out; }","typeGuard":"function isMasked(v: unknown): v is '***' { return v === '***'; }","tryCatchPattern":null,"preventionTips":["Same rule as env keys: masks may round-trip only onto existing stored keys","Inject real tokens from a vault at submit time","Never template new servers from another server's masked GET response"],"tags":["mcp","secrets","masking","headers","http-400"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}