NationalSecurityAgency/ghidra · error · IllegalArgumentException
Overridden constructor must return same or subclass of origi
Error message
Overridden constructor must return same or subclass of original
What it means
Thrown by DependentServiceResolver.addClass() when a @DependentService method specifies an override() target whose class is not assignable from the method's return type. An override replaces a previously-registered factory for a given service class, so the new method must return the same class or a subclass of the target it overrides.
Source
Thrown at Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java:82
addClass(superIf);
}
for (Method m : cls.getDeclaredMethods()) {
DependentService annot = m.getAnnotation(DependentService.class);
if (annot == null) {
continue;
}
int mods = m.getModifiers();
if (Modifier.isStatic(mods)) {
throw new IllegalArgumentException("Constructor must be a non-static method");
}
Class<?> override = annot.override();
Class<?> rCls = m.getReturnType();
if (override != DependentService.Sentinel.class) {
if (!override.isAssignableFrom(rCls)) {
throw new IllegalArgumentException(
"Overridden constructor must return same or subclass of original");
}
depsByDependents.computeIfAbsent(override, o -> new HashSet<>()).add(rCls);
constructors.put(override, m);
}
constructors.put(rCls, m);
m.setAccessible(true);
for (Class<?> pType : m.getParameterTypes()) {
depsByDependents.computeIfAbsent(rCls, c -> new HashSet<>()).add(pType);
}
}
for (Field f : cls.getDeclaredFields()) {
DependentService annot = f.getAnnotation(DependentService.class);
if (annot == null) {
continue;
}
Class<?> fCls = f.getType();View on GitHub (pinned to d5f144c24d)
Solutions
- Make the @DependentService method's return type the same as, or a subclass of, the override() target class.
- If overriding an interface, ensure the method returns a type that implements that interface.
- Correct the override() value to match the actual service hierarchy the method belongs to.
Example fix
// before
@DependentService(override = MyService.class)
public UnrelatedService alt() { ... } // UnrelatedService not a MyService
// after
@DependentService(override = MyService.class)
public MyServiceImpl alt() { ... } // MyServiceImpl extends MyService Defensive patterns
Strategy: validation
Validate before calling
Class<?> override = annot.override();
Class<?> rCls = m.getReturnType();
if (override != DependentService.Sentinel.class &&
!override.isAssignableFrom(rCls)) {
throw new IllegalStateException(
"override " + override + " not satisfied by return type " + rCls);
} Prevention
- Ensure override() targets are supertypes of the method's return type.
- Add a resolver-construction unit test per override.
- Review override targets when changing a return type.
When it happens
Trigger: Writing @DependentService(override=SomeService.class) on a method whose return type is unrelated to SomeService. Overriding a service but returning a sibling type rather than a subclass. Changing the override target without updating the method's return type.
Common situations: Plugin extension points where a plugin overrides a core service with an alternate implementation; refactoring an override's return type to a parallel hierarchy; mismatches between an interface and a concrete override.
Related errors
- Constructor method must return type assignable to the class
- Value '{address}' does not evaluate to an int
- Property ${propertyName} is not object type
- Cannot convert register value: ({class}) '{val}'
- Error constructing dependent service via {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/4e6ae81bd3c8f6b4.
Report an issue: GitHub.