{"record":{"id":"f3ffdd28222dd9e1","repo":"jenkinsci/jenkins","slug":"postconstruct-s","errorCode":null,"errorMessage":"@PostConstruct %s","messagePattern":"@PostConstruct (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/hudson/ExtensionFinder.java","lineNumber":640,"sourceCode":"\n                final Set<Class<?>> interfaces = ClassUtils.getAllInterfacesAsSet(instance);\n\n                while (c != Object.class) {\n                    Arrays.stream(c.getDeclaredMethods())\n                            .map(m -> getMethodAndInterfaceDeclarations(m, interfaces))\n                            .flatMap(Collection::stream)\n                            .filter(m -> m.getAnnotation(PostConstruct.class) != null || m.getAnnotation(javax.annotation.PostConstruct.class) != null)\n                            .findFirst()\n                            .ifPresent(methods::addFirst);\n                    c = c.getSuperclass();\n                }\n\n                for (Method postConstruct : methods) {\n                    try {\n                        postConstruct.setAccessible(true);\n                        postConstruct.invoke(instance);\n                    } catch (final Exception e) {\n                        throw new RuntimeException(String.format(\"@PostConstruct %s\", postConstruct), e);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Returns initial {@link Method} as well as all matching ones found in interfaces.\n     * This allows to introspect metadata for a method which is both declared in parent class and in implemented\n     * interface(s). {@code interfaces} typically is obtained by {@link ClassUtils#getAllInterfacesAsSet}\n     */\n    Collection<Method> getMethodAndInterfaceDeclarations(Method method, Collection<Class<?>> interfaces) {\n        final List<Method> methods = new ArrayList<>();\n        methods.add(method);\n\n        // we search for matching method by iteration and comparison vs getMethod to avoid repeated NoSuchMethodException\n        // being thrown, while interface typically only define a few set of methods to check.\n        interfaces.stream()","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/jenkinsci/jenkins/blob/2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc/core/src/main/java/hudson/ExtensionFinder.java#L622-L658","documentation":"Thrown by GuiceExtensionResolver.onProvision when invoking a @PostConstruct-annotated method on a freshly created extension instance throws. Jenkins collects all @PostConstruct methods across the class hierarchy and invokes them after Guice provisioning; any reflective invocation failure is wrapped in a RuntimeException naming the method.","triggerScenarios":"A @PostConstruct method on an extension throws (NPE, resource init failure, denied permission); the method is not accessible and setAccessible fails; the method requires arguments (illegal) causing IllegalArgumentException; provisioning order means a dependency is not ready.","commonSituations":"Extension's @PostConstruct opens a DB/file/network resource that is unavailable; extension assumes another singleton is already initialized but ordering differs; @PostConstruct added to a private method that the JVM refuses to make accessible under a strict module path.","solutions":["Read the cause and the method name in the message to locate the failing @PostConstruct.","Make the @PostConstruct method defensive: try/catch around risky init, or move lazy logic.","Ensure the method is non-private, takes no arguments, and returns void per JSR-250.","Verify any singleton it depends on is registered and loaded first."],"exampleFix":"// before\n@PostConstruct\npublic void init() { this.conn = ds.getConnection(); } // throws if DB down\n// after\n@PostConstruct\npublic void init() {\n    try { this.conn = ds.getConnection(); }\n    catch (SQLException e) { LOGGER.log(Level.WARNING, \"no DB\", e); }\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"static boolean isPostConstructSafe(Method m) {\n    return m.getParameterCount() == 0 && m.getReturnType() == void.class;\n}","tryCatchPattern":"try {\n    // extension provisioning that runs @PostConstruct\n} catch (RuntimeException e) {\n    if (e.getMessage().startsWith(\"@PostConstruct\")) {\n        // defensive: log and continue, or mark the extension failed\n    } else throw e;\n}","preventionTips":["Make @PostConstruct methods defensive with internal try/catch for risky resource init.","Ensure @PostConstruct methods take no args, return void, and are not private.","Avoid ordering assumptions; do not assume another extension is initialized first."],"tags":["guice","postconstruct","lifecycle"],"backgroundTag":null,"analyzedSha":"2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc","analyzedAt":"2026-08-14T07:07:15.274Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}