guzzle/guzzle · error · RuntimeException
value is not a non-negative decimal integer
Error message
value is not a non-negative decimal integer
What it means
Thrown by HeaderProcessor::parseContentLength() when a Content-Length value, after trimming spaces/tabs and splitting on commas, does not match ^[0-9]+$. Content-Length must be a single non-negative decimal integer; signed, decimal, hex, or empty values are rejected per RFC 7230. The same validator runs for both request and response Content-Length.
Solutions
- Inspect the actual Content-Length header on the wire (curl -v, on_headers) to see the malformed value.
- Remove any manually set Content-Length on the request and let Guzzle compute it from the body size.
- Report the malformed header to the server/CDN operator.
- Catch RuntimeException when you must interoperate with the broken endpoint.
Example fix
// before - manually forcing a bad length
$request = new \GuzzleHttp\Psr7\Request('POST', $url, ['Content-Length' => '1.5'], $body);
// after - let Guzzle derive the length
$request = new \GuzzleHttp\Psr7\Request('POST', $url, [], $body); Defensive patterns
Strategy: try-catch
Validate before calling
// For request-side Content-Length, never set it manually; let Guzzle compute it.
// If you must set it, validate first:
if ($cl !== null && preg_match('/^[0-9]+$/D', (string) $cl) !== 1) {
throw new \InvalidArgumentException('Bad Content-Length');
} Type guard
function isValidContentLength(?string $value): bool {
return $value === null || preg_match('/^[0-9]+$/D', $value) === 1;
} Try / catch
try {
$response = $client->get($url);
} catch (\RuntimeException $e) {
if (str_contains($e->getMessage(), 'not a non-negative decimal integer')) {
// surface the bad header value to logs
}
throw $e;
} Prevention
- Never set Content-Length manually on requests; let Guzzle derive it from the body.
- Use on_headers to inspect server-sent Content-Length during debugging.
- Report malformed server headers to the endpoint owner.
When it happens
Trigger: A server sends 'Content-Length: 1.5', 'Content-Length: -5', 'Content-Length: 0x10', 'Content-Length:' (empty), or 'Content-Length: 1024;' (trailing semicolon). Also triggered on the request side when a caller sets Content-Length to a non-integer string.
Common situations: Origin server bug, a CDN rewriting bodies but leaving a stale/decimal length, custom middleware setting Content-Length to a computed float, or proxy concatenation producing malformed values.
Related errors
- Invalid Content-Length response header
- A response must not contain both Content-Length and…
- Content-Length exceeds the maximum integer size supported…
- HTTP header line is invalid
- values conflict
AI-assisted analysis of guzzle/guzzle@d1cbca7697 (2026-08-06).
Data as JSON: /api/errors/7be6800f840fd28c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Handler/HeaderProcessor.php:114
return \preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*(?:\r\n|\r|\n)?$/D', \trim($parts[1], " \t")) === 1;
}
/**
* Returns a normalized decimal Content-Length, or null when absent.
*
* @param string[] $values
*
* @throws \RuntimeException when Content-Length is malformed or conflicting.
*/
public static function parseContentLength(array $values): ?string
{
$length = null;
foreach ($values as $value) {
foreach (\explode(',', $value) as $part) {
$part = \trim($part, " \t");
if (\preg_match('/^[0-9]+$/D', $part) !== 1) {
throw new \RuntimeException('value is not a non-negative decimal integer');
}
$part = \ltrim($part, '0');
$part = $part === '' ? '0' : $part;
if ($length !== null && $part !== $length) {
throw new \RuntimeException('values conflict');
}
$length = $part;
}
}
if ($length === null) {
return null;
}
return $length;
}View on GitHub (pinned to d1cbca7697)