{"record":{"id":"6ae07b5401f1c477","repo":"NationalSecurityAgency/ghidra","slug":"no-service-constructor-for","errorCode":null,"errorMessage":"No service constructor for {}","messagePattern":"No service constructor for (.+?)","errorType":"exception","errorClass":"ServiceConstructionException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java","lineNumber":160,"sourceCode":"\t\t\tif (service == null) {\n\t\t\t\tservice = cons.construct(obj, instancesByClass);\n\t\t\t\tconstructed.put(cons.method, service);\n\t\t\t}\n\t\t\tinstancesByClass.put(cons.cls, service);\n\t\t\tSet<Field> fields = fieldsByClass.remove(cons.cls);\n\t\t\tif (fields != null) {\n\t\t\t\tfor (Field f : fields) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tf.set(obj, service);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (IllegalArgumentException | IllegalAccessException e) {\n\t\t\t\t\t\tthrow new AssertionError(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!fieldsByClass.isEmpty()) {\n\t\t\tthrow new ServiceConstructionException(\n\t\t\t\t\"No service constructor for \" + fieldsByClass.keySet(), null);\n\t\t}\n\t}\n}\n","sourceCodeStart":142,"sourceCodeEnd":165,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java#L142-L165","documentation":"Thrown by DependentServiceResolver.injectServices() as a ServiceConstructionException when, after running all ordered constructors, some @DependentService field types still have no constructed instance to inject. This is a defensive post-condition: compile() should normally prevent it, so hitting it signals an inconsistency between the compiled order and the field set (e.g. a field type that has a producer key but whose service instance was never populated during the run).","triggerScenarios":"A field type whose producer was registered under a different class key than the field's declared type. An override mapping that shadows the real producer. A scenario where two field types share a producer method but only one gets keyed into instancesByClass. Generally an internal/edge inconsistency rather than a simple missing producer (that is error 568).","commonSituations":"Complex override configurations; field types that are supertypes of the produced class but not the exact key used; partial refactors of the DI registration that leave the field map and constructor map out of sync.","solutions":["Verify each @DependentService field's declared type exactly matches (or is the override key of) a registered producer's return type.","Review override() mappings to ensure they do not hide the producer the field needs.","Simplify the DI graph and re-add fields incrementally to isolate the offending field.","Report with the fieldsByClass key set from the message to identify the unpopulated field types."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  DependentServiceResolver.inject(obj);\n} catch (ServiceConstructionException e) {\n  if (e.getMessage().startsWith(\"No service constructor for\")) {\n    Msg.error(this, \"Injection incomplete; unpopulated fields: \" + e.getMessage());\n  } else throw e;\n}","preventionTips":["Keep field types exactly matching producer return types or override keys.","Simplify DI graphs when overrides are involved.","Add resolver smoke tests for complex override configurations."],"tags":["ghidra","dependency-injection","injection-failure","postcondition"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}