pinpoint-apm/pinpoint · error · RuntimeException

${after} method not found. ${Arrays.toString(afterParamList)

Error message

${after} method not found. ${Arrays.toString(afterParamList)}

What it means

InterceptorDefinitionFactory.buildInterceptorDefinition validates the @Interceptee before/after methods declared on an interceptor class. When the configured 'after' method name cannot be found on the target interceptor class with the expected parameter list, it throws this RuntimeException. This happens because the weave-time contract requires both before and after methods to resolve to real Methods before bytecode instrumentation is generated.

Source

Thrown at agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/interceptor/InterceptorDefinitionFactory.java:188

            if(!this.interceptorClazz.isAssignableFrom(targetClazz)) {
                return null;
            }
            @SuppressWarnings("unchecked")
            final Class<? extends Interceptor> casting = (Class<? extends Interceptor>) targetClazz;
            return createInterceptorDefinition(casting);
        }

        private InterceptorDefinition createInterceptorDefinition(Class<? extends Interceptor> targetInterceptorClazz) {

            final Method beforeMethod = searchMethod(targetInterceptorClazz, before, beforeParamList);
            if (beforeMethod == null) {
                throw new RuntimeException(before + " method not found. " + Arrays.toString(beforeParamList));
            }
            final boolean beforeIgnoreMethod = beforeMethod.isAnnotationPresent(IgnoreMethod.class);
            final boolean blockType = beforeMethod.getReturnType() == TraceBlock.class;
            final Method afterMethod = searchMethod(targetInterceptorClazz, after, afterParamList);
            if (afterMethod == null) {
                throw new RuntimeException(after + " method not found. " + Arrays.toString(afterParamList));
            }
            final boolean afterIgnoreMethod = afterMethod.isAnnotationPresent(IgnoreMethod.class);

            if (interceptorType == InterceptorType.RESULT_REPLACE && afterMethod.getReturnType() != Object.class) {
                // a covariant override would change the weaved call descriptor and break the INVOKEINTERFACE site.
                throw new RuntimeException(after + " must return java.lang.Object. " + targetInterceptorClazz.getName());
            }

            if (beforeIgnoreMethod && afterIgnoreMethod) {
                return new DefaultInterceptorDefinition(interceptorClazz, targetInterceptorClazz, interceptorType, CaptureType.NON, null, null);
            }
            if (beforeIgnoreMethod) {
                if (blockType) {
                    throw new RuntimeException(before + " not allowed return. " + Arrays.toString(beforeParamList));
                }
                return new DefaultInterceptorDefinition(interceptorClazz, targetInterceptorClazz, interceptorType, CaptureType.AFTER, null, afterMethod);
            }
            if (afterIgnoreMethod) {

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Check the after method name in the @Interceptee annotation matches an actual method on the interceptor class exactly
  2. Compare the after method signature with the required parameter list printed in the error message and fix parameter types/order
  3. If the method is inherited, verify it is declared on the targetInterceptorClazz hierarchy that searchMethod can reach (public/protected, correct class)
  4. Rebuild/redeploy the agent plugin so the compiled interceptor matches the annotation

Example fix

// before
@Interceptee(before="before", after="aftr")
class MyInterceptor { public void before(...) {} public void after(...) {} }
// after
@Interceptee(before="before", after="after")
class MyInterceptor { public void before(...) {} public void after(...) {} }
Defensive patterns

Strategy: validation

Validate before calling

Method m = Arrays.stream(interceptorClazz.getMethods()).filter(x -> x.getName().equals(after) && Arrays.equals(x.getParameterTypes(), paramTypes)).findFirst().orElse(null);
if (m == null) throw new IllegalStateException("after method missing: " + after);

Try / catch

try { def = factory.buildInterceptorDefinition(...); } catch (RuntimeException e) { log.error("bad interceptor def: {}", e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Calling createInterceptorDefinition (via InterceptorDefinitionFactory) with an interceptor class whose @Interceptee 'after' value names a method that does not exist on the class, or whose parameter types do not match afterParamList (e.g. wrong signature, renamed method, wrong parameter order).

Common situations: Typos in the after method name; copying an interceptor and renaming methods without updating the annotation; signature drift after adding a parameter to the interceptor constructor/after method; writing a custom interceptor whose after signature does not match the chosen InterceptorType.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/0f4e864cdad64714. Report an issue: GitHub.