psf/requests · error · InvalidHeader

Invalid leading whitespace, reserved character(s), or return

Error message

Invalid leading whitespace, reserved character(s), or return character(s) in header {header_kind}: {header_part!r}

What it means

Raised as `requests.exceptions.InvalidHeader` from `_validate_header_part()` in `src/requests/utils.py:1116` when a header name or value fails the `_HEADER_VALIDATORS_STR`/`_HEADER_VALIDATORS_BYTE` regex. These validators reject leading whitespace and CR/LF (return) characters in values, and reserved/illegal characters in names. This is primarily a security control against HTTP header injection (request smuggling / response splitting via embedded '\r\n'), added after CVE-2022-32213-class issues across HTTP clients.

Source

Thrown at src/requests/utils.py:1116

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
    """
    scheme, netloc, path, params, query, _fragment = urlparse(url)

    # see func:`prepend_scheme_if_needed`
    if not netloc:
        netloc, path = path, netloc

    netloc = netloc.rsplit("@", 1)[-1]

View on GitHub ↗ (pinned to 414f0513c3)

Solutions

  1. Strip the value: `headers={'Authorization': token.strip()}` — newlines from `read()` or env vars are the most common cause.
  2. Never place raw user input into headers; sanitize or reject values containing '\r' or '\n'.
  3. Remove the colon or spaces from the header name — pass 'Authorization', not 'Authorization:'.
  4. If the value is legitimately multi-line, it cannot be a single HTTP header; restructure (e.g. base64-encode it).

Example fix

# before
token = open('token.txt').read()  # ends with '\n'
requests.get(url, headers={'Authorization': f'Bearer {token}'})
# after
token = open('token.txt').read().strip()
requests.get(url, headers={'Authorization': f'Bearer {token}'})
Defensive patterns

Strategy: validation

Validate before calling

import re
_INVALID = re.compile(r'^\s|[\r\n]')
def header_value_is_safe(value):
    s = value.decode('latin-1') if isinstance(value, bytes) else value
    return not _INVALID.search(s)

assert all(header_value_is_safe(v) for v in headers.values()), 'header contains leading whitespace or CR/LF'

Try / catch

try:
    resp = requests.get(url, headers=headers)
except requests.exceptions.InvalidHeader as e:
    # leading whitespace or CR/LF in a header — often an injection attempt
    log.warning('Rejected unsafe header: %s', e)

Prevention

When it happens

Trigger: Any request where a header value contains '\r' or '\n' (e.g. `headers={'X-Note': 'line1\nline2'}`), starts with a space or tab, or where a header name contains characters outside the RFC 7230 token set (spaces, colons, non-ASCII). The message's `header_kind` tells you whether the name or the value failed.

Common situations: Header values read from files or env vars that carry a trailing/embedded newline (e.g. `open('token.txt').read()` without `.strip()`); user input interpolated into headers (injection attempt or accident); multi-line strings from YAML config; copy-pasted tokens with leading whitespace; header names with a stray trailing colon like 'Authorization:'.

Related errors


AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31). Data as JSON: /data/errors/b89494c0d9bf600f.json. Report an issue: GitHub ↗.