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

  1. Remove the `Authorization` entry from `headers` and rely on `auth: oauth` for credentials.
  2. Or remove `"auth": "oauth"` and keep the static Authorization header for token-based auth.
  3. Note the check is case-insensitive, so renaming to `authorization` or `AUTHORIZATION` will not bypass it.
  4. 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

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


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/a4c9f14b4467a18b. Report an issue: GitHub.