can1357/oh-my-pi · error · HTTPException
invalid content-length
Error message
invalid content-length
What it means
_read_body_capped reads request bodies with a size cap. If a Content-Length header is present but not a valid integer (int(cl) raises ValueError), the proxy returns HTTP 400 'invalid content-length'. This protects downstream size enforcement from silently ignoring a malformed header.
Source
Thrown at python/robomp/src/proxy/server.py:423
return f"{request.url.path}?{query}" if query else request.url.path
async def _read_body_capped(request: Request) -> bytes:
"""Read the request body with a hard byte cap.
Checks `Content-Length` first (cheap reject before any read), then
streams chunks via `request.stream()` with a running counter so a
client that lies about (or omits) the header still can't get more
than `max_bytes` into memory. We deliberately do NOT call
`request.body()` first — that would buffer the full payload before
auth checks ever run.
"""
max_bytes = settings.gh_proxy_max_body_bytes
cl = request.headers.get("content-length")
if cl is not None:
try:
declared = int(cl)
except ValueError as exc:
raise HTTPException(400, "invalid content-length") from exc
if declared > max_bytes:
raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, "request body too large")
chunks: list[bytes] = []
total = 0
async for chunk in request.stream():
if not chunk:
continue
total += len(chunk)
if total > max_bytes:
raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, "request body too large")
chunks.append(chunk)
body = b"".join(chunks)
# Starlette's `request.body()` / `request.json()` re-read from
# `request._body`. We consumed the stream above, so seed the cache
# to keep downstream JSON parsing working without a second read.
request._body = body # type: ignore[attr-defined]
return body
View on GitHub (pinned to 9690622007)
Solutions
- Fix the client to send a valid decimal Content-Length (or omit it and use chunked transfer-encoding)
- Inspect intermediate proxies/CDNs that may rewrite the header and fix their configuration
- Test with curl or a standard HTTP library, which always emits a correct Content-Length for fixed bodies
Example fix
// before
headers: { "Content-Length": String(body.length) + " bytes" }
// after
headers: { "Content-Length": String(body.length) } Defensive patterns
Strategy: validation
Validate before calling
const cl = headers["content-length"];
if (cl !== undefined && !/^\d+$/.test(cl)) throw new Error(`invalid content-length: ${cl}`); Type guard
function isValidContentLength(v: unknown): v is string {
return typeof v === "string" && /^\d+$/.test(v);
} Prevention
- Let your HTTP client set Content-Length automatically
- Audit middleware/proxies that rewrite or duplicate headers
- Use standard HTTP libraries rather than hand-rolled request writers
When it happens
Trigger: Sending a request to an authenticated gh-proxy endpoint with a Content-Length header that is not a decimal integer, e.g. 'Content-Length: abc', '10, 20', or a header containing units like '10 bytes'.
Common situations: Misconfigured proxies/clients emitting duplicate or malformed Content-Length; hand-rolled HTTP clients writing the header manually; fuzzing or non-conformant middleware rewriting headers.
Related errors
- Gemini Files API upload initialization response is missing X
- Codex live signaling returned no valid call ID
- missing/invalid 'slot_uid'
- invalid '{field}': must be array of strings
- missing/invalid 'comments'
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/9be666332f468dc6.
Report an issue: GitHub.