langchain-ai/deepagents · error · ValueError
Server '{server_name}' cannot combine 'auth: oauth' with an
Error message
Server '{server_name}' cannot combine 'auth: oauth' with an 'Authorization' header. What it means
`auth: oauth` manages credentials itself (token storage and refresh), and supplying a static `Authorization` header alongside it creates two competing sources of credentials for the same request. `_validate_server_config` raises this ValueError when an http/sse server sets `auth: oauth` while its `headers` contain a case-insensitive `Authorization` key.
Source
Thrown at libs/code/deepagents_code/mcp_tools.py:955
if auth != "oauth":
msg = (
f"Server '{server_name}' has unsupported auth value "
f"{auth!r}. Only 'oauth' is supported."
)
raise ValueError(msg)
if server_type == "stdio":
msg = (
f"Server '{server_name}' uses stdio transport; "
"'auth: oauth' is only valid for http/sse transports."
)
raise ValueError(msg)
header_names = {name.lower() for name in (server_config.get("headers") or {})}
if "authorization" in header_names:
msg = (
f"Server '{server_name}' cannot combine 'auth: oauth' "
"with an 'Authorization' header."
)
raise ValueError(msg)
_validate_tool_filter_fields(server_name, server_config)
def _validate_tool_filter_fields(
server_name: str,
server_config: dict[str, Any],
) -> None:
"""Validate optional `allowedTools` / `disabledTools` fields.
Both fields, when present, must be non-empty lists of strings. Setting
both on the same server is rejected to keep the filter semantics
unambiguous. An empty list is rejected because it would silently strip
every tool from the server (`allowedTools`) or be a no-op
(`disabledTools`) — both are almost certainly user errors; omit the field
instead.
Args:View on GitHub (pinned to a1af029e6e)
Solutions
- Remove the `Authorization` entry from `headers` and rely on `auth: oauth` for credentials.
- Or remove `"auth": "oauth"` and keep the static Authorization header for token-based auth.
- Note the check is case-insensitive, so renaming to `authorization` or `AUTHORIZATION` will not bypass it.
- Re-run `resolve_and_load_mcp_tools` after the fix to confirm validation passes.
Example fix
// before
{"api": {"type": "http", "url": "https://mcp.example.com", "auth": "oauth", "headers": {"Authorization": "Bearer tok"}}}
// after
{"api": {"type": "http", "url": "https://mcp.example.com", "auth": "oauth"}} Defensive patterns
Strategy: validation
Validate before calling
def validate_no_auth_header_conflict(name: str, cfg: dict) -> None:
if cfg.get("auth") == "oauth":
names = {str(k).lower() for k in (cfg.get("headers") or {})}
if "authorization" in names:
raise ValueError(f"Server '{name}' cannot combine 'auth: oauth' with an 'Authorization' header.") Type guard
def auth_and_headers_compatible(cfg: dict) -> bool:
if cfg.get("auth") != "oauth":
return True
names = {str(k).lower() for k in (cfg.get("headers") or {})}
return "authorization" not in names Try / catch
try:
tools = resolve_and_load_mcp_tools(config)
except ValueError as e:
if "cannot combine 'auth: oauth'" in str(e):
name = extract_server_name(str(e))
headers = config["servers"][name].get("headers", {})
headers = {k: v for k, v in headers.items() if k.lower() != "authorization"}
config["servers"][name]["headers"] = headers
tools = resolve_and_load_mcp_tools(config)
else:
raise Prevention
- Pick one credential source per server: either `auth: oauth` or a static Authorization header, never both.
- When migrating a token-header server to OAuth, delete the Authorization header in the same change.
- The check is case-insensitive — renaming the header will not bypass it.
- Document per-server auth mode in your config to prevent template drift.
When it happens
Trigger: An http/sse server entry has both `"auth": "oauth"` and a headers dict containing `Authorization` (any casing, e.g. `authorization` or `AUTHORIZATION`), validated via `select_server`, `resolve_and_load_mcp_tools`, or the batch validators.
Common situations: Adding `auth: oauth` to a server that already used a static bearer token in headers; migrating from token auth to OAuth without deleting the old header; a shared config template that ships both options.
Related errors
- Server '{server_name}' has unsupported auth value {auth!r}.
- Server '{server_name}' uses stdio transport; 'auth: oauth' i
- {str(exc)}
- Server '{server_name}' header {name!r} must be a string, got
- MCPReauthRequiredError({server_name})
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/a4c9f14b4467a18b.
Report an issue: GitHub.