FoundationAgents/MetaGPT · error · TypeError
Header values must be strings
Error message
Header values must be strings
What it means
Companion check in _validate_headers: the dict's keys are strings, but at least one value is not. HTTP header values must be strings, so ints, bools, None, lists, or dicts as values raise this TypeError before the request goes out.
Source
Thrown at metagpt/provider/general_api_base.py:433
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]]:
abs_url = "%s%s" % (self.base_url, url)
headers = self._validate_headers(supplied_headers)View on GitHub (pinned to 11cdf466d0)
Solutions
- Stringify every value: {k: str(v) for k, v in headers.items()}.
- For booleans use "true"/"false" strings explicitly instead of YAML bare true/false.
- Drop or default None values: {k: v for k, v in headers.items() if v is not None}.
- Quote numeric header values in YAML so they load as strings.
Example fix
# before (config2.yaml) default_headers: X-Temperature: 0.7 # float -> TypeError # after default_headers: X-Temperature: "0.7"
Defensive patterns
Strategy: type-guard
Validate before calling
headers = {k: ("" if v is None else str(v)) for k, v in raw_headers.items()}
assert all(isinstance(v, str) for v in headers.values()) Type guard
def has_string_values(h: Dict[str, Any]) -> TypeGuard[Dict[str, str]]:
return isinstance(h, dict) and all(isinstance(v, str) for v in h.values()) Try / catch
try:
validated = requestor._validate_headers(headers)
except TypeError as e:
if "values" in str(e):
headers = {k: str(v) for k, v in headers.items()}
validated = requestor._validate_headers(headers)
else:
raise Prevention
- Quote all header values in YAML
- Replace None header values with empty string or drop the key
- Cast bools to "true"/"false" strings explicitly
When it happens
Trigger: Passing headers like {"X-Max-Retries": 3}, {"X-Debug": True}, or {"Authorization": None} to a provider request; any non-str value triggers the raise even if other values are fine.
Common situations: Config-driven headers where YAML auto-types values (true -> bool, 42 -> int), header templates with unfilled placeholders set to None, or passing a token read as bytes instead of str.
Related errors
- Headers must be a dictionary
- Header keys must be strings
- use `review` after `fill`
- Only support for python, markdown, but got {language}
- Only support for language: python, markdown, but got {langua
AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14).
Data as JSON: /api/errors/9f99d405d3b45281.
Report an issue: GitHub.