symfony/http-foundation · error · InvalidArgumentException
Cannot anonymize more than 4 bytes for IPv4 and 16 bytes…
Error message
Cannot anonymize more than 4 bytes for IPv4 and 16 bytes for IPv6.
What it means
IpUtils::anonymize() caps truncation at 4 bytes for IPv4 and 16 bytes for IPv6, because that is the entire address; anything larger is meaningless and would attempt to shift more bits than exist. Passing an exceeding byte count throws this InvalidArgumentException before any anonymization happens.
Solutions
- Clamp per family: $v4Bytes = min(4, $v4Bytes); $v6Bytes = min(16, $v6Bytes);
- If the goal is full anonymization, pass the exact maxima: anonymize($ip, 4, 16).
- Separate the IPv4 and IPv6 byte settings in your configuration instead of sharing one value.
- Validate config-supplied integers against int<0,4> / int<0,16> at load time.
- Use filter_var to detect address family first and apply only the matching limit.
Example fix
// before IpUtils::anonymize($ip, $bytes, $bytes); // $bytes = 16: v4 limit is 4, throws // after IpUtils::anonymize($ip, min(4, $bytes), min(16, $bytes));
Defensive patterns
Strategy: validation
Validate before calling
// before calling anonymize $v4Bytes = min(4, max(0, (int) $v4Bytes)); $v6Bytes = min(16, max(0, (int) $v6Bytes)); IpUtils::anonymize($ip, $v4Bytes, $v6Bytes);
Type guard
function isValidAnonymizeBytes(int $v4, int $v6): bool {
return $v4 >= 0 && $v4 <= 4 && $v6 >= 0 && $v6 <= 16;
} Try / catch
try {
$anon = IpUtils::anonymize($ip, $v4Bytes, $v6Bytes);
} catch (\InvalidArgumentException $e) {
$anon = IpUtils::anonymize($ip, 4, 16); // full anonymization fallback
} Prevention
- Never share one byte-count config value across IPv4 and IPv6; clamp each to its own cap.
- Use min(4, ...) for v4 and min(16, ...) for v6 at the call site.
- For 'fully anonymize', pass the exact maxima 4 and 16.
- Document the per-family limits next to your privacy configuration keys.
When it happens
Trigger: Calling IpUtils::anonymize($ip, 5) or IpUtils::anonymize($ip, 4, 17); using a single shared 'bytes' config value applied to both IPv4 and IPv6 without clamping to each limit (e.g. 8 or 16 bytes, valid for v6 but over the v4 cap of 4).
Common situations: One privacy config (e.g. 'anonymize: 16') fed to both v4/v6 arguments; developers assuming the limit is uniform across families; off-by-one when the intent was 'anonymize fully' (use 4/16 exactly).
Related errors
- Cannot anonymize less than 0 bytes.
- The "sameSite" parameter value is not valid.
- The cookie name " " uses a reserved prefix, which requires…
- The cookie name " " uses the "__Host-" prefix, which…
- The cookie name " " uses the "__Host-" prefix, which…
AI-assisted analysis of symfony/http-foundation@5aea19cd67 (2026-09-13).
Data as JSON: /api/errors/854065df6766bb4d.
Report an issue: GitHub.
Appendix: source
Thrown at IpUtils.php:214
return self::setCacheResult($cacheKey, true);
}
/**
* Anonymizes an IP/IPv6.
*
* Removes the last bytes of IPv4 and IPv6 addresses (1 byte for IPv4 and 8 bytes for IPv6 by default).
*
* @param int<0, 4> $v4Bytes
* @param int<0, 16> $v6Bytes
*/
public static function anonymize(string $ip, int $v4Bytes = 1, int $v6Bytes = 8): string
{
if ($v4Bytes < 0 || $v6Bytes < 0) {
throw new \InvalidArgumentException('Cannot anonymize less than 0 bytes.');
}
if ($v4Bytes > 4 || $v6Bytes > 16) {
throw new \InvalidArgumentException('Cannot anonymize more than 4 bytes for IPv4 and 16 bytes for IPv6.');
}
/*
* If the IP contains a % symbol, then it is a local-link address with scoping according to RFC 4007
* In that case, we only care about the part before the % symbol, as the following functions, can only work with
* the IP address itself. As the scope can leak information (containing interface name), we do not want to
* include it in our anonymized IP data.
*/
if (str_contains($ip, '%')) {
$ip = substr($ip, 0, strpos($ip, '%'));
}
$wrappedIPv6 = false;
if (str_starts_with($ip, '[') && str_ends_with($ip, ']')) {
$wrappedIPv6 = true;
$ip = substr($ip, 1, -1);
}
View on GitHub (pinned to 5aea19cd67)