jenkinsci/jenkins · error · RuntimeException
@PostConstruct %s
Error message
@PostConstruct %s
What it means
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.
Source
Thrown at core/src/main/java/hudson/ExtensionFinder.java:640
final Set<Class<?>> interfaces = ClassUtils.getAllInterfacesAsSet(instance);
while (c != Object.class) {
Arrays.stream(c.getDeclaredMethods())
.map(m -> getMethodAndInterfaceDeclarations(m, interfaces))
.flatMap(Collection::stream)
.filter(m -> m.getAnnotation(PostConstruct.class) != null || m.getAnnotation(javax.annotation.PostConstruct.class) != null)
.findFirst()
.ifPresent(methods::addFirst);
c = c.getSuperclass();
}
for (Method postConstruct : methods) {
try {
postConstruct.setAccessible(true);
postConstruct.invoke(instance);
} catch (final Exception e) {
throw new RuntimeException(String.format("@PostConstruct %s", postConstruct), e);
}
}
}
}
}
/**
* Returns initial {@link Method} as well as all matching ones found in interfaces.
* This allows to introspect metadata for a method which is both declared in parent class and in implemented
* interface(s). {@code interfaces} typically is obtained by {@link ClassUtils#getAllInterfacesAsSet}
*/
Collection<Method> getMethodAndInterfaceDeclarations(Method method, Collection<Class<?>> interfaces) {
final List<Method> methods = new ArrayList<>();
methods.add(method);
// we search for matching method by iteration and comparison vs getMethod to avoid repeated NoSuchMethodException
// being thrown, while interface typically only define a few set of methods to check.
interfaces.stream()View on GitHub (pinned to 2e228ff40b)
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.
Example fix
// before
@PostConstruct
public void init() { this.conn = ds.getConnection(); } // throws if DB down
// after
@PostConstruct
public void init() {
try { this.conn = ds.getConnection(); }
catch (SQLException e) { LOGGER.log(Level.WARNING, "no DB", e); }
} Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
static boolean isPostConstructSafe(Method m) {
return m.getParameterCount() == 0 && m.getReturnType() == void.class;
} Try / catch
try {
// extension provisioning that runs @PostConstruct
} catch (RuntimeException e) {
if (e.getMessage().startsWith("@PostConstruct")) {
// defensive: log and continue, or mark the extension failed
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {} doesn't extend from hudson.Plugin
- Failed to initialize
- Failed to resolve ${c}
- The class ${type.getName()} was not found, potentially not y
- This Jenkins lifecycle does not support dynamic loading of p
AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14).
Data as JSON: /api/errors/f3ffdd28222dd9e1.
Report an issue: GitHub.