projectlombok/lombok · error · DelegateRecursion
@Delegate does not support recursion (delegating to a type…
Error message
@Delegate does not support recursion (delegating to a type that itself has @Delegate members). Member "%s" is @Delegate in type "%s"
What it means
PatchDelegate refuses to compile code where a type annotated with @Delegate delegates to another type that itself contains @Delegate members. Recursive delegation cannot be resolved, so Eclipse's patched compiler throws DelegateRecursion with the member and type names.
Solutions
- Remove @Delegate from one level of the delegation chain
- Replace @Delegate with explicit handwritten forwarding methods on the middle type
- Delegate only to the leaf type directly instead of stacking delegates
- Upgrade Lombok — newer versions may handle some recursion cases
Example fix
// before
class A { @Delegate B b; }
class B { @Delegate C c; }
// after
class A { @Delegate B b; }
class B { private C c; C getC() { return c; } } // explicit method instead of @Delegate Defensive patterns
Strategy: validation
Validate before calling
function hasRecursiveDelegate(chain) {
for (const t of chain) {
if (chain.some(o => o !== t && t.delegatesTo.includes(o.name) && o.hasDelegateMembers)) return true;
}
return false;
} Prevention
- Never stack @Delegate on types that themselves use @Delegate
- Search the codebase for @Delegate usages before adding a new one to a delegated-to type
- Use explicit forwarding methods when two levels of delegation are needed
When it happens
Trigger: Class A has @Delegate on a field of type B, and B (or a supertype in B's hierarchy being scanned) also has @Delegate members — the recursion guard in canDelegate throws.
Common situations: Chained delegation patterns (A delegates to B, B delegates to C), DTO wrappers wrapping other @Delegate wrappers, copying delegation-heavy code between classes.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- @Delegate does not support recursion (delegating to a type…
- I can't make sense of this annotation value. Try using a…
- Expected a single value, but
- Can't translate to an enum of type
- Can't translate to a class object.
AI-assisted analysis of projectlombok/lombok@6d6a3e9fec (2026-09-07).
Data as JSON: /api/errors/bfbd3d0e18f29f0d.
Report an issue: GitHub.
Appendix: source
Thrown at src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java:1022
for (Binding b : bindings) {
AnnotationBinding[] anns = null;
if (b instanceof MethodBinding) anns = ((MethodBinding) b).getAnnotations();
if (b instanceof FieldBinding) anns = ((FieldBinding) b).getAnnotations();
// anns = b.getAnnotations() would make a heck of a lot more sense, but that is a late addition to ecj, so would cause NoSuchMethodErrors! Don't use that!
if (anns == null) continue;
for (AnnotationBinding ann : anns) {
char[][] name = null;
try {
name = ann.getAnnotationType().compoundName;
} catch (Exception ignore) {}
if (name == null || name.length < 2 || name.length > 3) continue;
if (!Arrays.equals(STRING_LOMBOK, name[0])) continue;
if (!Arrays.equals(STRING_DELEGATE, name[name.length - 1])) continue;
if (name.length == 3 && !Arrays.equals(STRING_EXPERIMENTAL, name[1])) continue;
throw new DelegateRecursion(parent.readableName(), b.readableName());
}
}
}
private static final class BindingTuple {
BindingTuple(MethodBinding parameterized, MethodBinding base, char[] fieldName, ASTNode responsible) {
this.parameterized = parameterized;
this.base = base;
this.fieldName = fieldName;
this.responsible = responsible;
}
final MethodBinding parameterized, base;
final char[] fieldName;
final ASTNode responsible;
@Override public String toString() {
return String.format("{param: %s, base: %s, fieldName: %s}", parameterized == null ? "(null)" : printSig(parameterized), base == null ? "(null)" : printSig(base), new String(fieldName));View on GitHub (pinned to 6d6a3e9fec)