FoundationAgents/MetaGPT · error · TypeError
Header keys must be strings
Error message
Header keys must be strings
What it means
Raised inside _validate_headers while iterating supplied headers: the container is a dict, but at least one key is not a str. Header keys become HTTP header names, so non-string keys (int, tuple, bytes) are rejected client-side before the request is sent.
Source
Thrown at metagpt/provider/general_api_base.py:431
if self.api_version is not None and self.api_type == ApiType.OPEN_AI:
headers["LLM-Version"] = self.api_version
if request_id is not None:
headers["X-Request-Id"] = request_id
headers.update(extra)
return headers
def _validate_headers(self, supplied_headers: Optional[Dict[str, str]]) -> Dict[str, str]:
headers: Dict[str, str] = {}
if supplied_headers is None:
return headers
if not isinstance(supplied_headers, dict):
raise TypeError("Headers must be a dictionary")
for k, v in supplied_headers.items():
if not isinstance(k, str):
raise TypeError("Header keys must be strings")
if not isinstance(v, str):
raise TypeError("Header values must be strings")
headers[k] = v
# NOTE: It is possible to do more validation of the headers, but a request could always
# be made to the API manually with invalid headers, so we need to handle them server side.
return headers
def _prepare_request_raw(
self,
url,
supplied_headers,
method,
params,
files,
request_id: Optional[str],
) -> Tuple[str, Dict[str, str], Optional[bytes]]:View on GitHub (pinned to 11cdf466d0)
Solutions
- Convert all header keys to strings: {str(k): v for k, v in headers.items()}.
- For bytes keys, decode first: {k.decode(): v for k, v in headers.items()}.
- Replace numeric or tuple keys with the intended header names (e.g. "X-Request-Id").
- Add a startup assertion that all(isinstance(k, str) for k in headers).
Example fix
# before
headers = {1: "application/json"} # int key -> TypeError
# after
headers = {"1": "application/json"} # or {str(k): v for k, v in headers.items()} Defensive patterns
Strategy: type-guard
Validate before calling
headers = {str(k): v for k, v in raw_headers.items()}
assert all(isinstance(k, str) for k in headers) Type guard
def has_string_keys(h: Dict[Any, Any]) -> TypeGuard[Dict[str, Any]]:
return isinstance(h, dict) and all(isinstance(k, str) for k in h) Try / catch
try:
validated = requestor._validate_headers(headers)
except TypeError:
headers = {str(k): str(v) for k, v in headers.items()}
validated = requestor._validate_headers(headers) Prevention
- Build headers only from string literals or str() calls
- Decode bytes keys before assembling header dicts
- Lint for non-literal dict keys in header-building code
When it happens
Trigger: Passing a dict with non-string keys such as {8080: "true"}, {("a", "b"): "v"}, or {b"X-Trace": "1"} as default_headers/supplied_headers to any request through the general API base.
Common situations: Building headers dynamically from numeric IDs or enum values without str() conversion, mixing Python 2-style bytes keys into a ported codebase, or using dict(zip(range(...), values)) by mistake.
Related errors
- Headers must be a dictionary
- Header values must be strings
- Only support for python, markdown, but got {language}
- Only support for language: python, markdown, but got {langua
- The invoice format is not zip, pdf, png, or jpg
AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14).
Data as JSON: /api/errors/3e0fcf823ac6c1c8.
Report an issue: GitHub.