bazelbuild/bazel · error · IllegalArgumentException
Class %s has two selfCall methods defined
Error message
Class %s has two selfCall methods defined
What it means
A Starlark value class may expose at most one @StarlarkMethod(selfCall = true) method, because selfCall defines what happens when the value itself is called like a function. CallUtils scans all annotated methods and throws this IllegalArgumentException if it finds two non-synthetic selfCall methods (synthetic bridge methods from covariant overrides are tolerated).
Source
Thrown at src/main/java/net/starlark/java/eval/CallUtils.java:367
// enabled by semantics?
if (!manager
.getSemantics()
.isFeatureEnabledBasedOnTogglingFlags(
callable.enableOnlyWithFlag(), callable.disableWithFlag())) {
continue;
}
MethodDescriptor descriptor = MethodDescriptor.of(manager, method, callable);
// self-call method?
if (callable.selfCall()) {
if (selfCall == null) {
selfCall = descriptor;
} else if (!method.isSynthetic()) {
// Two distinct selfCall methods. (A synthetic bridge of the same method -- e.g. from a
// covariant return override -- is not a conflict and is simply ignored.)
throw new IllegalArgumentException(
String.format("Class %s has two selfCall methods defined", clazz.getName()));
}
continue;
}
// regular method
methods.putIfAbsent(callable.name(), descriptor);
}
ClassDescriptor classDescriptor = new ClassDescriptor();
classDescriptor.manager = manager;
classDescriptor.selfCall = selfCall;
classDescriptor.methods = ImmutableMap.copyOf(methods);
classDescriptor.typeConstructor = associatedTypeConstructor;
if (getFixedStarlarkType(clazz) == null && wantStarlarkBuiltinAutoType(clazz)) {
if (classDescriptor.typeConstructor == null) {
classDescriptor.typeConstructor =
Types.wrapType(View on GitHub (pinned to e6e199d060)
Solutions
- Keep exactly one @StarlarkMethod(selfCall = true) method; remove the annotation (or set selfCall = false) on the other.
- Delete the overriding duplicate and rely on the inherited selfCall method.
- If both operations must remain, expose the second as a regular named method.
Example fix
// before
class F implements StarlarkValue {
@StarlarkMethod(selfCall = true) public Object call() {...}
@StarlarkMethod(selfCall = true) public Object invoke() {...}
}
// after
class F implements StarlarkValue {
@StarlarkMethod(selfCall = true) public Object call() {...}
@StarlarkMethod(name="invoke") public Object invoke() {...}
} Defensive patterns
Strategy: validation
Validate before calling
// Assert exactly one selfCall method before first use
static void checkSingleSelfCall(Class<?> c) {
int n = 0;
for (Method m : c.getMethods()) {
StarlarkMethod a = m.getAnnotation(StarlarkMethod.class);
if (a != null && a.selfCall()) n++;
}
if (n > 1) throw new IllegalArgumentException(c + " has " + n + " selfCall methods");
} Prevention
- Mark exactly one method selfCall = true per value type.
- After refactoring callable types, grep for 'selfCall = true' across the hierarchy.
- Include descriptor-building in unit tests for new Starlark types.
When it happens
Trigger: Two methods annotated @StarlarkMethod(selfCall = true) on the same class, or one local plus one inherited annotated selfCall method; implementing a callable interface while also annotating the class's own call method as selfCall.
Common situations: Refactoring from a call() convention to selfCall without removing the old annotation; combining two callable base types; copy-pasting an annotated method into a subclass.
Related errors
- Expected one of %s and %s to be a subclass of the other
- Class %s has an incompatible overload of annotated method %s
- Class %s has multiple overloaded methods named '%s' annotate
- %s missing getStarlarkType(StarlarkSemantics) method
- Class %s has multiple methods named getAssociatedTypeConstru
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/b0d2166e44e3d778.
Report an issue: GitHub.