D4Vinci/Scrapling · error · ValueError

Could not parse header without colon: '{header_line}'.

Error message

Could not parse header without colon: '{header_line}'.

What it means

Raised by `_ParseHeaders` in scrapling/core/utils/_shell.py:31, the parser behind the `scrapling` CLI/shell `-H/--header` flags. Each header line must either contain a colon (`Key: Value`) or end with a bare semicolon (`Key;`) which is treated as a valueless header. A line with neither a colon nor a trailing semicolon cannot be split into name/value, so a ValueError is raised with the offending line echoed.

Source

Thrown at scrapling/core/utils/_shell.py:31

    cookie_parser = Cookie.SimpleCookie()
    cookie_parser.load(cookie_string)
    for key, morsel in cookie_parser.items():
        yield key, morsel.value


def _ParseHeaders(header_lines: List[str], parse_cookies: bool = True) -> Tuple[Dict[str, str], Dict[str, str]]:
    """Parses headers into separate header and cookie dictionaries."""
    header_dict = dict()
    cookie_dict = dict()

    for header_line in header_lines:
        if ":" not in header_line:
            if header_line.endswith(";"):
                header_key = header_line[:-1].strip()
                header_value = ""
                header_dict[header_key] = header_value
            else:
                raise ValueError(f"Could not parse header without colon: '{header_line}'.")
        else:
            header_key, header_value = header_line.split(":", 1)
            header_key = header_key.strip()
            header_value = header_value.strip()

            if parse_cookies:
                if header_key.lower() == "cookie":
                    try:
                        cookie_dict = {key: value for key, value in _CookieParser(header_value)}
                    except Exception as e:  # pragma: no cover
                        raise ValueError(f"Could not parse cookie string from header '{header_value}': {e}")
                else:
                    header_dict[header_key] = header_value
            else:
                header_dict[header_key] = header_value

    return header_dict, cookie_dict

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Write headers in `Name: Value` form: `scrapling shell -H 'Content-Type: application/json' URL`.
  2. For valueless headers, append a semicolon: `-H 'accept-encoding;'`.
  3. Quote each `-H` argument fully in your shell so colons and spaces survive.
  4. If headers come from a file, strip blank lines and lines without `:` before passing them.

Example fix

# before
scrapling shell -H 'Accept application/json' https://example.com

# after
scrapling shell -H 'Accept: application/json' https://example.com
Defensive patterns

Strategy: validation

Validate before calling

def normalize_header_lines(lines: list[str]) -> list[str]:
    out = []
    for line in lines:
        line = line.strip()
        if not line:
            continue
        if ':' not in line and not line.endswith(';'):
            raise ValueError(f"Header line missing ':': {line!r}")
        out.append(line)
    return out

Try / catch

from scrapling.core.utils._shell import _ParseHeaders
try:
    headers, cookies = _ParseHeaders(header_lines)
except ValueError as e:
    print(f'Fix header syntax (need "Name: Value" or "Name;"): {e}')
    raise

Prevention

When it happens

Trigger: Running `scrapling shell -H 'Accept-Encoding gzip' url` (space instead of colon), `-H 'UserAgent: Mozilla/5.0'` without a colon after a typo, or `-H 'accept'` (bare header name without trailing `;`). Also triggered programmatically by calling `_ParseHeaders(['bad line'])`.

Common situations: Copying header lines from a browser 'Copy all headers' block and losing the colon; shell-quoting issues that mangle `-H` values (e.g. splitting `X-Custom: a:b` across args so only `X-Custom` survives); passing a URL accidentally as a header argument.

Related errors


AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14). Data as JSON: /api/errors/fda2eeaf0a122861. Report an issue: GitHub.