{"record":{"id":"b0d2166e44e3d778","repo":"bazelbuild/bazel","slug":"class-s-has-two-selfcall-methods-defined","errorCode":null,"errorMessage":"Class %s has two selfCall methods defined","messagePattern":"Class (.+?) has two selfCall methods defined","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/net/starlark/java/eval/CallUtils.java","lineNumber":367,"sourceCode":"\n      // enabled by semantics?\n      if (!manager\n          .getSemantics()\n          .isFeatureEnabledBasedOnTogglingFlags(\n              callable.enableOnlyWithFlag(), callable.disableWithFlag())) {\n        continue;\n      }\n\n      MethodDescriptor descriptor = MethodDescriptor.of(manager, method, callable);\n\n      // self-call method?\n      if (callable.selfCall()) {\n        if (selfCall == null) {\n          selfCall = descriptor;\n        } else if (!method.isSynthetic()) {\n          // Two distinct selfCall methods. (A synthetic bridge of the same method -- e.g. from a\n          // covariant return override -- is not a conflict and is simply ignored.)\n          throw new IllegalArgumentException(\n              String.format(\"Class %s has two selfCall methods defined\", clazz.getName()));\n        }\n        continue;\n      }\n\n      // regular method\n      methods.putIfAbsent(callable.name(), descriptor);\n    }\n\n    ClassDescriptor classDescriptor = new ClassDescriptor();\n    classDescriptor.manager = manager;\n    classDescriptor.selfCall = selfCall;\n    classDescriptor.methods = ImmutableMap.copyOf(methods);\n    classDescriptor.typeConstructor = associatedTypeConstructor;\n    if (getFixedStarlarkType(clazz) == null && wantStarlarkBuiltinAutoType(clazz)) {\n      if (classDescriptor.typeConstructor == null) {\n        classDescriptor.typeConstructor =\n            Types.wrapType(","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/net/starlark/java/eval/CallUtils.java#L349-L385","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclass F implements StarlarkValue {\n  @StarlarkMethod(selfCall = true) public Object call() {...}\n  @StarlarkMethod(selfCall = true) public Object invoke() {...}\n}\n\n// after\nclass F implements StarlarkValue {\n  @StarlarkMethod(selfCall = true) public Object call() {...}\n  @StarlarkMethod(name=\"invoke\") public Object invoke() {...}\n}","handlingStrategy":"validation","validationCode":"// Assert exactly one selfCall method before first use\nstatic void checkSingleSelfCall(Class<?> c) {\n  int n = 0;\n  for (Method m : c.getMethods()) {\n    StarlarkMethod a = m.getAnnotation(StarlarkMethod.class);\n    if (a != null && a.selfCall()) n++;\n  }\n  if (n > 1) throw new IllegalArgumentException(c + \" has \" + n + \" selfCall methods\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["starlark","annotations","self-call","java"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}