{"record":{"id":"8091ca19ef7e3980","repo":"hibernate/hibernate-orm","slug":"cannot-inject-dependency-service","errorCode":null,"errorMessage":"Cannot inject dependency service","messagePattern":"Cannot inject dependency service","errorType":"exception","errorClass":"ServiceDependencyException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java","lineNumber":329,"sourceCode":"\t\t\t@Nonnull Method injectionMethod,\n\t\t\t@Nonnull InjectService injectService,\n\t\t\t@Nonnull Class<? extends Service> dependentServiceRole) {\n\t\t// todo : because of the use of proxies, this is no longer returning null here...\n\n\t\tfinal var dependantService = getService( dependentServiceRole );\n\t\tif ( dependantService == null ) {\n\t\t\tif ( injectService.required() ) {\n\t\t\t\tthrow new ServiceDependencyException(\n\t\t\t\t\t\t\"Dependency [\" + dependentServiceRole + \"] declared by service [\" + service + \"] not found\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\ttry {\n\t\t\t\tinjectionMethod.invoke( service, dependantService );\n\t\t\t}\n\t\t\tcatch ( Exception e ) {\n\t\t\t\tthrow new ServiceDependencyException( \"Cannot inject dependency service\", e );\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static Class<? extends Service> dependentServiceRole(\n\t\t\t@Nonnull Method injectionMethod,\n\t\t\t@Nonnull InjectService injectService) {\n\t\tfinal var parameterTypes = injectionMethod.getParameterTypes();\n\t\tif ( injectionMethod.getParameterCount() != 1 ) {\n\t\t\tthrow new ServiceDependencyException(\n\t\t\t\t\t\"Encountered @InjectService on method with unexpected number of parameters\"\n\t\t\t);\n\t\t}\n\n\t\tfinal var dependentServiceRole = injectService.serviceRole();\n\t\tif ( dependentServiceRole == null\n\t\t\t\t|| Void.class.equals( dependentServiceRole )  // old default value\n\t\t\t\t|| Service.class.equals( dependentServiceRole ) ) {  // new default value","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/service/internal/AbstractServiceRegistryImpl.java#L311-L347","documentation":"After resolving a dependent service, Hibernate invokes the @InjectService setter via reflection (Method.invoke). Any failure — usually the setter itself throwing (InvocationTargetException), or an access/type mismatch — is wrapped as ServiceDependencyException(\"Cannot inject dependency service\") with the real cause attached. The injection target code is the first place to look.","triggerScenarios":"An @InjectService setter that throws during assignment (e.g., null-checking or validation logic inside the setter); a non-public setter that reflection cannot invoke on the runtime's module rules; a parameter type that does not match the resolved service instance.","commonSituations":"Setters with defensive logic that rejects the injected instance; JDK/module access restrictions in JPMS or GraalVM native images; service implementations whose concrete type differs from the setter parameter after refactors.","solutions":["Unwrap and read the InvocationTargetException cause — it names the failing line inside your setter","Keep @InjectService setters public and trivial: assign the field, nothing else","Match the setter parameter type to the service role interface exactly","Move validation logic out of the setter into the service's start()/post-injection phase"],"exampleFix":"// before\n@InjectService\npublic void setJdbcServices(JdbcServices jdbcServices) {\n    Objects.requireNonNull(jdbcServices.getDialect()); // throws -> 'Cannot inject dependency service'\n    this.jdbcServices = jdbcServices;\n}\n\n// after\n@InjectService\npublic void setJdbcServices(JdbcServices jdbcServices) {\n    this.jdbcServices = jdbcServices; // validate later, in start()\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    registry.requireService(MyService.class);\n}\ncatch (ServiceDependencyException e) {\n    Throwable inner = e.getCause(); // InvocationTargetException -> your setter's exception\n    Throwable real = inner instanceof InvocationTargetException ite ? ite.getTargetException() : inner;\n    throw new IllegalStateException(\"injection setter failed: \" + real, real);\n}","preventionTips":["Keep @InjectService setters public and trivial (plain field assignment)","Never validate or throw inside injection setters; defer to start()","Match setter parameter types to the service role interface exactly"],"tags":["service-registry","dependency-injection","reflection"],"backgroundTag":"dependency-injection-failure","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}