Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

requests.exceptions.InvalidHeader: Header part invalid in Python Requests

Verified FixPython 3.10+requests 2.x / urllib3Silo: requests

Quick Fix / Solution Rapide

Ensure all dictionary keys and values in headers are strictly Python str (or bytes), and remove invalid control characters like leading colons or newlines.

Root Cause Analysis

This error occurs when Python's requests or urllib3 library validates an HTTP request header dictionary, but one of the header names or values is not a string (such as an integer, boolean True, or None), or contains forbidden HTTP header byte characters like carriage returns (\r), newlines (\n), or leading colons.

HTTP Specification Header Rules (RFC 7230 / RFC 9110)

According to the HTTP protocol specifications, headers must consist strictly of US-ASCII strings. requests and urllib3 enforce strict type checking on header tuples before constructing the wire byte stream:

  1. Non-String Python Objects: Passing headers={'Sec-GPC': 1} or headers={'X-Cache-Enabled': True} fails because the integer 1 or boolean True has no defined HTTP wire encoding.
  2. Copied HTTP/2 Pseudo-Headers: Copying raw headers from browser Developer Tools that include pseudo-headers starting with a colon (such as :authority, :method, :path, :scheme).
  3. Header Injection Control Characters: Values containing unescaped newline \n or carriage return \r characters, which are blocked as HTTP response splitting / header injection vulnerabilities.

Reproduction Code (MCVE)

Example: Bug Reproduction
import requests
from requests.exceptions import InvalidHeader

# Simulates passing a non-string boolean header value in requests
raw_headers = {'Sec-GPC': True}
for key, val in raw_headers.items():
    if not isinstance(val, (str, bytes)):
        raise InvalidHeader(f"Header part (1) from ({repr(key)}, {repr(val)}) invalid: header value must be str or bytes, not {type(val).__name__}")

Solution 1: Explicitly Convert Header Values to Strings

Cast all header keys and values to str before passing the dictionary to requests.get() or requests.Session().

Example: Recommended Solution
import requests

raw_headers = {
    'User-Agent': 'PythonFix-Client/1.0',
    'Sec-GPC': True,
    'X-Request-ID': 10492,
    'X-Timeout-Sec': 30.5
}

# Sanitize header dictionary: cast all keys and values to string
clean_headers = {str(k): str(v) for k, v in raw_headers.items() if not str(k).startswith(':')}

print(f'Sanitized headers ready for requests: {clean_headers}')

Solution 2: Strip HTTP/2 Pseudo-Headers Copied from Browser Tools

Filter out colon-prefixed pseudo-headers (:path, :authority) when pasting headers from browser devtools.

Example: Alternative Solution
copied_browser_headers = {
    ':authority': 'api.example.com',
    ':method': 'GET',
    ':path': '/v1/users',
    'Accept': 'application/json',
    'Authorization': 'Bearer sample-token'
}

# Filter out pseudo-headers starting with ':'
valid_http1_headers = {
    k: str(v) for k, v in copied_browser_headers.items()
    if not k.startswith(':')
}

print(f'Valid HTTP/1.1 headers: {valid_http1_headers}')

Common Pitfalls & Edge Cases

Passing None as a header value (e.g. headers={'Authorization': None}) raises InvalidHeader. If you want to omit an optional header or remove a default session header, use del session.headers['Authorization'] or pass headers={'Authorization': None} only if using a custom wrapper that explicitly drops None keys.

Contrasting InvalidHeader with related errors:

  • requests.exceptions.InvalidHeader: Header contains non-str type or forbidden byte characters.
  • requests.exceptions.InvalidURL: The URL scheme or domain name format is malformed.
  • requests.exceptions.ConnectionError: The network socket failed to reach the server.