langchain-ai/deepagents · error · TypeError

{prefix}.{name} must be a dictionary, got {type(values).__na

Error message

{prefix}.{name} must be a dictionary, got {type(values).__name__}

What it means

resolve_mcp_server_env validates the resolved `env` and `headers` fields of an MCP server config before resolving templated values. If either field resolves to anything other than a dictionary (e.g. a list, string, or null), this TypeError is thrown. The library enforces the MCP config schema: env/headers must be string-keyed mappings.

Source

Thrown at libs/code/deepagents_code/mcp_config.py:173

            resolved[name] = _resolve_string(resolved[name], field=f"{prefix}.{name}")

    if "args" in resolved:
        args = resolved["args"]
        if not isinstance(args, list):
            msg = f"{prefix}.args must be a list, got {type(args).__name__}"
            raise TypeError(msg)
        resolved["args"] = [
            _resolve_string(value, field=f"{prefix}.args[{index}]")
            for index, value in enumerate(args)
        ]

    for name in ("env", "headers"):
        if name not in resolved:
            continue
        values = resolved[name]
        if not isinstance(values, dict):
            msg = f"{prefix}.{name} must be a dictionary, got {type(values).__name__}"
            raise TypeError(msg)
        resolved[name] = _resolve_mapping_values(values, field=f"{prefix}.{name}")

    return resolved

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Fix the server config so `env` and `headers` are mappings of string keys to string values (e.g. `env: {API_KEY: 'x'}` not `env: ['API_KEY=x']`).
  2. Check for null: a key with no value (`headers:` with nothing after it) resolves to None; give it at least `{}`.
  3. If configs are merged from multiple sources, verify the winning layer defines these fields as dictionaries.
  4. Run `dcode mcp login list` / the test entrypoint to validate the config before reconnecting.

Example fix

# before (config)
env:
  - API_KEY=secret
# after
env:
  API_KEY: secret
Defensive patterns

Strategy: type-guard

Validate before calling

for field in ("env", "headers"):
    value = server_config.get(field, {})
    if not isinstance(value, dict):
        raise TypeError(f"{server_name}.{field} must be a dictionary, got {type(value).__name__}")

Type guard

def is_str_mapping(value: object) -> TypeGuard[dict[str, str]]:
    return isinstance(value, dict) and all(isinstance(k, str) and isinstance(v, str) for k, v in value.items())

Try / catch

try:
    env = resolve_mcp_server_env(server)
except TypeError as exc:
    print(f"Bad MCP config for {server_name}: {exc}; fix env/headers to be mappings")

Prevention

When it happens

Trigger: Calling resolve_mcp_server_env (directly or via run_mcp_login_list, resolve_headers, login, or _preflight_and_connect) with an MCP server config where `env` or `headers` is a list, string, or other non-dict value after config resolution.

Common situations: A typo'd YAML/TOML config that defines `env` as a list of `KEY=VALUE` strings instead of a mapping; a project-level mcp.json with `headers: []`; merging configs that replace the dict with null; hand-editing config files with wrong indentation.

Related errors


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