psf/requests · error · InvalidHeader
Header part ({header_part!r}) from {header} must be of type
Error message
Header part ({header_part!r}) from {header} must be of type str or bytes, not {type(header_part)} What it means
Raised as `requests.exceptions.InvalidHeader` from `_validate_header_part()` in `src/requests/utils.py:1109`. Before sending, requests validates every header name and value via `check_header_validity()`; each part must be `str` or `bytes` so it can be matched against the appropriate regex validator. Any other type (int, None, list, dict, etc.) cannot be validated or serialized onto the wire, so requests fails fast instead of sending a malformed header.
Source
Thrown at src/requests/utils.py:1109
:param header: tuple, in the format (name, value).
"""
name, value = header
_validate_header_part(header, name, 0)
_validate_header_part(header, value, 1)
def _validate_header_part(
header: tuple[str | bytes, str | bytes],
header_part: str | bytes,
header_validator_index: int,
) -> None:
if isinstance(header_part, str):
validator = _HEADER_VALIDATORS_STR[header_validator_index]
elif isinstance(header_part, bytes):
# runtime guard for non-str/bytes input
validator = _HEADER_VALIDATORS_BYTE[header_validator_index]
else:
raise InvalidHeader(
f"Header part ({header_part!r}) from {header} "
f"must be of type str or bytes, not {type(header_part)}"
)
if not validator.match(header_part): # type: ignore[arg-type]
header_kind = "name" if header_validator_index == 0 else "value"
raise InvalidHeader(
f"Invalid leading whitespace, reserved character(s), or return "
f"character(s) in header {header_kind}: {header_part!r}"
)
def urldefragauth(url: str) -> str:
"""
Given a url remove the fragment and the authentication part.
:rtype: str
"""View on GitHub ↗ (pinned to 414f0513c3)
Solutions
- Convert the offending header value to a string: `headers={'X-Retry-Count': str(3)}` — the exception message shows exactly which part and its type.
- If loading headers from config/JSON, coerce all values with `{k: str(v) for k, v in headers.items() if v is not None}`.
- To remove a default header on a Session, delete it (`del session.headers['Accept-Encoding']`) rather than setting it to None per-request only works at the Session level — per-request None is invalid.
- For multiple values, join them yourself: `', '.join(values)`.
Example fix
# before
requests.get(url, headers={'X-Request-Id': uuid.uuid4(), 'X-Retries': 3})
# after
requests.get(url, headers={'X-Request-Id': str(uuid.uuid4()), 'X-Retries': '3'}) Defensive patterns
Strategy: type-guard
Validate before calling
def headers_are_valid_types(headers):
return all(isinstance(k, (str, bytes)) and isinstance(v, (str, bytes)) for k, v in headers.items()) Type guard
def is_header_part(value):
"""Requests requires header names/values to be str or bytes."""
return isinstance(value, (str, bytes)) Try / catch
try:
resp = requests.get(url, headers=headers)
except requests.exceptions.InvalidHeader as e:
log.error('Header has wrong type: %s', e) Prevention
- Convert non-string header values explicitly (str(value)) before building the headers dict — ints, None, and objects are rejected
- Type-check header dicts at your API boundary, especially when values come from config files or JSON
- Don't put None in a header value to 'unset' a default unless you intend requests' skip-header behavior; audit those cases
When it happens
Trigger: Passing a non-string header value or name in the `headers=` dict of any request call, e.g. `requests.get(url, headers={'X-Retry-Count': 3})` or `{'Authorization': None}` (when set per-request rather than deleted), or setting `session.headers['X-Id'] = uuid.uuid4()` without str().
Common situations: Numeric values (ports, counts, timestamps) placed directly into headers without str(); values loaded from JSON/YAML config that parse as int/bool/None; passing a `uuid.UUID`, `datetime`, or f-string forgotten object; accidentally assigning a list of values instead of a comma-joined string.
Related errors
- Invalid leading whitespace, reserved character(s), or return
- Files must be provided.
- Data must not be a string.
- Invalid URL {url!r}: No scheme supplied. Perhaps you meant h
- URL has an invalid label.
AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31).
Data as JSON: /data/errors/3463071ff348f5e6.json.
Report an issue: GitHub ↗.