{"record":{"id":"4e6ae81bd3c8f6b4","repo":"NationalSecurityAgency/ghidra","slug":"overridden-constructor-must-return-same-or-subclas","errorCode":null,"errorMessage":"Overridden constructor must return same or subclass of original","messagePattern":"Overridden constructor must return same or subclass of original","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java","lineNumber":82,"sourceCode":"\t\t\taddClass(superIf);\n\t\t}\n\n\t\tfor (Method m : cls.getDeclaredMethods()) {\n\t\t\tDependentService annot = m.getAnnotation(DependentService.class);\n\t\t\tif (annot == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tint mods = m.getModifiers();\n\t\t\tif (Modifier.isStatic(mods)) {\n\t\t\t\tthrow new IllegalArgumentException(\"Constructor must be a non-static method\");\n\t\t\t}\n\n\t\t\tClass<?> override = annot.override();\n\t\t\tClass<?> rCls = m.getReturnType();\n\t\t\tif (override != DependentService.Sentinel.class) {\n\t\t\t\tif (!override.isAssignableFrom(rCls)) {\n\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Overridden constructor must return same or subclass of original\");\n\t\t\t\t}\n\t\t\t\tdepsByDependents.computeIfAbsent(override, o -> new HashSet<>()).add(rCls);\n\t\t\t\tconstructors.put(override, m);\n\t\t\t}\n\t\t\tconstructors.put(rCls, m);\n\t\t\tm.setAccessible(true);\n\n\t\t\tfor (Class<?> pType : m.getParameterTypes()) {\n\t\t\t\tdepsByDependents.computeIfAbsent(rCls, c -> new HashSet<>()).add(pType);\n\t\t\t}\n\t\t}\n\t\tfor (Field f : cls.getDeclaredFields()) {\n\t\t\tDependentService annot = f.getAnnotation(DependentService.class);\n\t\t\tif (annot == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tClass<?> fCls = f.getType();","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java#L64-L100","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n@DependentService(override = MyService.class)\npublic UnrelatedService alt() { ... } // UnrelatedService not a MyService\n\n// after\n@DependentService(override = MyService.class)\npublic MyServiceImpl alt() { ... } // MyServiceImpl extends MyService","handlingStrategy":"validation","validationCode":"Class<?> override = annot.override();\nClass<?> rCls = m.getReturnType();\nif (override != DependentService.Sentinel.class &&\n    !override.isAssignableFrom(rCls)) {\n  throw new IllegalStateException(\n    \"override \" + override + \" not satisfied by return type \" + rCls);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["ghidra","dependency-injection","override","type-mismatch"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}