{"record":{"id":"dada7e9b02c2f932","repo":"NationalSecurityAgency/ghidra","slug":"there-are-fields-without-suitable-constructors","errorCode":null,"errorMessage":"There are fields without suitable constructors: {}","messagePattern":"There are fields without suitable constructors: (.+?)","errorType":"exception","errorClass":"UnsatisfiedFieldsException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java","lineNumber":110,"sourceCode":"\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();\n\t\t\tfieldsByClass.computeIfAbsent(fCls, c -> new HashSet<>()).add(f);\n\t\t\tf.setAccessible(true);\n\t\t}\n\t}\n\n\tprivate void compile() throws UnsatisfiedParameterException, UnsatisfiedFieldsException {\n\t\tSet<Class<?>> missing = new HashSet<>(fieldsByClass.keySet());\n\t\tmissing.removeAll(constructors.keySet());\n\t\tif (!missing.isEmpty()) {\n\t\t\tthrow new UnsatisfiedFieldsException(missing);\n\t\t}\n\t\tSet<Class<?>> unordered = new HashSet<>(constructors.keySet());\n\t\twhile (!unordered.isEmpty()) {\n\t\t\tSet<Class<?>> forRound = new HashSet<>(unordered);\n\t\t\tforRound.removeAll(depsByDependents.keySet());\n\t\t\tif (forRound.isEmpty()) {\n\t\t\t\tthrow new UnsatisfiedParameterException(unordered);\n\t\t\t}\n\t\t\tfor (Class<?> ready : forRound) {\n\t\t\t\tMethod m = constructors.get(ready);\n\t\t\t\tunordered.remove(ready);\n\t\t\t\tordered.add(new DependentServiceConstructor<>(ready, m));\n\t\t\t\tfor (Iterator<Set<Class<?>>> iterator =\n\t\t\t\t\tdepsByDependents.values().iterator(); iterator.hasNext();) {\n\t\t\t\t\tSet<Class<?>> deps = iterator.next();\n\t\t\t\t\tdeps.remove(ready);\n\t\t\t\t\tif (deps.isEmpty()) {\n\t\t\t\t\t\titerator.remove();","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/ProposedUtils/src/main/java/generic/depends/DependentServiceResolver.java#L92-L128","documentation":"Thrown by DependentServiceResolver.compile() as an UnsatisfiedFieldsException when one or more @DependentService-annotated fields have a type for which no @DependentService factory method (constructor) was registered. Every injected field must have a matching producer, otherwise the resolver cannot populate it. The exception carries the set of unsatisfied field types.","triggerScenarios":"Annotating a field with @DependentService but never writing a @DependentService method that returns that field's type. Removing a factory method while leaving its consuming field in place. Field type is an interface whose only producer was deleted.","commonSituations":"Adding a new dependency field and forgetting the producer; refactoring that renames/moves a service class so the field type no longer matches any return type; incomplete feature branches.","solutions":["Add a @DependentService method whose return type matches each unsatisfied field type reported in the exception.","Remove the @DependentService annotation from fields you no longer want injected.","If the field type is an interface, ensure some method returns a concrete implementation assignable to it.","Inspect the exception's missing set to see exactly which types lack producers."],"exampleFix":"// before\npublic class Owner {\n  @DependentService private Thing thing; // no method returns Thing\n}\n\n// after\npublic class Owner {\n  @DependentService private Thing thing;\n\n  @DependentService\n  public Thing buildThing() { return new ThingImpl(); } // producer added\n}","handlingStrategy":"validation","validationCode":"Set<Class<?>> fieldTypes = collectDependentFieldTypes(cls);\nSet<Class<?>> producedTypes = collectDependentReturnTypes(cls);\nif (!fieldTypes.containsAll(producedTypes == null ? fieldTypes : fieldTypes)) {\n  // simpler: ensure every field type has a producer\n}\nfieldTypes.removeAll(producedTypes);\nif (!fieldTypes.isEmpty()) {\n  throw new IllegalStateException(\"No producer for fields: \" + fieldTypes);\n}","typeGuard":null,"tryCatchPattern":"try {\n  DependentServiceResolver.get(cls);\n} catch (UnsatisfiedFieldsException e) {\n  Msg.error(this, \"Unsatisfied @DependentService fields: \" + e.getMissing());\n}","preventionTips":["Add a producer for every @DependentService field type.","Remove annotations from fields you stop injecting.","Run the resolver in a unit test whenever fields change."],"tags":["ghidra","dependency-injection","missing-producer","fields"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}