netty/netty · error · IllegalArgumentException
can't add to itself.
Error message
can't add to itself.
What it means
Thrown by DefaultHeaders.add(Headers) when the argument is the same instance as 'this' (headers == this). Adding a collection to itself would cause infinite recursion or concurrent modification in the linked-list traversal during addImpl(), so Netty rejects it explicitly. The check is a reference equality (==) check, not a deep equality check.
Source
Thrown at codec-base/src/main/java/io/netty/handler/codec/DefaultHeaders.java:479
@Override
public T addFloat(K name, float value) {
return add(name, fromFloat(name, value));
}
@Override
public T addByte(K name, byte value) {
return add(name, fromByte(name, value));
}
@Override
public T addShort(K name, short value) {
return add(name, fromShort(name, value));
}
@Override
public T add(Headers<? extends K, ? extends V, ?> headers) {
if (headers == this) {
throw new IllegalArgumentException("can't add to itself.");
}
addImpl(headers);
return thisT();
}
protected void addImpl(Headers<? extends K, ? extends V, ?> headers) {
if (headers instanceof DefaultHeaders) {
@SuppressWarnings("unchecked")
final DefaultHeaders<? extends K, ? extends V, T> defaultHeaders =
(DefaultHeaders<? extends K, ? extends V, T>) headers;
HeaderEntry<? extends K, ? extends V> e = defaultHeaders.head.after;
if (defaultHeaders.hashingStrategy == hashingStrategy &&
defaultHeaders.nameValidator == nameValidator) {
// Fastest copy
while (e != defaultHeaders.head) {
add0(e.hash, index(e.hash), e.key, e.value);
e = e.after;
}View on GitHub (pinned to 70040aacae)
Solutions
- Before calling add(), check reference equality: if (source != target) target.add(source).
- If you need to duplicate entries within the same headers, iterate manually and add each entry.
- Use a separate headers instance as the merge destination.
Example fix
// before
if (needsMerge) {
headers.add(headers); // self-reference
}
// after
if (needsMerge && other != headers) {
headers.add(other);
} Defensive patterns
Strategy: validation
Validate before calling
// Prevent self-addition
public void mergeHeaders(DefaultHeaders<K, V, T> target, Headers<K, V, ?> source) {
if (source == target) {
throw new IllegalArgumentException("Cannot merge headers into itself");
}
target.add(source);
} Type guard
static <K, V> boolean isSelfReference(
DefaultHeaders<K, V, ?> target, Headers<K, V, ?> source) {
return source == target;
} Try / catch
try {
headers.add(source);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("can't add to itself")) {
// copy entries individually instead
for (Map.Entry<K, V> entry : source) {
headers.add(entry.getKey(), entry.getValue());
}
}
} Prevention
- Always check source != target before calling add().
- Use a separate destination instance for merge operations.
- Be careful with conditional merge paths that may resolve to the same reference.
When it happens
Trigger: Calling headers.add(headers) — passing the same DefaultHeaders instance as both source and destination. Occurs in code that copies headers between collections and accidentally passes the source as its own target, or in aggregation/merge logic where the same reference appears on both sides.
Common situations: Header merging/aggregation code where src and dst resolve to the same object due to a logic bug; conditional code paths that sometimes pass the same headers reference; refactoring that changed ownership semantics; a method that receives headers as a parameter and also returns to the same caller.
Related errors
- Can't have end < start
- Validation failed for header '{name}'
- Failed to convert object value for header '{name}'
- Failed to convert boolean value for header '{name}'
- Failed to convert byte value for header '{name}'
AI-assisted analysis of netty/netty@70040aacae (2026-08-14).
Data as JSON: /api/errors/a1856fd1dc0f44b1.
Report an issue: GitHub.