pinpoint-apm/pinpoint · error · RuntimeException

${before} not allowed return. ${Arrays.toString(beforeParamL

Error message

${before} not allowed return. ${Arrays.toString(beforeParamList)}

What it means

The before method was marked @IgnoreMethod (capturing skipped), yet it also has a TraceBlock return type. A block-type before method implies blocking interception around both phases, which is incompatible with ignoring the before capture, so the factory rejects this combination.

Source

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

            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) {
                if (blockType) {
                    throw new RuntimeException(after + " not allowed return. " + Arrays.toString(afterParamList));
                }
                return new DefaultInterceptorDefinition(interceptorClazz, targetInterceptorClazz, interceptorType, CaptureType.BEFORE, beforeMethod, null);
            }
            if (blockType) {
                return new DefaultInterceptorDefinition(interceptorClazz, targetInterceptorClazz, interceptorType, CaptureType.BLOCK_AROUND, beforeMethod, afterMethod);
            }

            return new DefaultInterceptorDefinition(interceptorClazz, targetInterceptorClazz, interceptorType, CaptureType.AROUND, beforeMethod, afterMethod);
        }

        private Method searchMethod(Class<?> interceptorClazz, String searchMethodName, Class<?>[] searchMethodParameter) {
            Objects.requireNonNull(searchMethodName, "searchMethodName");

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Remove @IgnoreMethod from the block-type before method so CaptureType.BLOCK_AROUND is selected
  2. Or remove the TraceBlock return type if the intent is truly a BEFORE-skipped (after-only) interceptor
  3. Adjust the InterceptorType so the before/after combination matches the intended capture semantics

Example fix

// before
@IgnoreMethod public TraceBlock before(Object target, Object[] args) { ... }
// after
public TraceBlock before(Object target, Object[] args) { ... }
Defensive patterns

Strategy: validation

Validate before calling

if (before.isAnnotationPresent(IgnoreMethod.class) && before.getReturnType() == TraceBlock.class) throw new IllegalStateException("IgnoreMethod + TraceBlock before not allowed");

Try / catch

try { def = factory.buildInterceptorDefinition(...); } catch (RuntimeException e) { log.error("invalid before/after ignore config: {}", e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Defining an interceptor where the before method is annotated @IgnoreMethod AND returns TraceBlock, then building its InterceptorDefinition (CaptureType.AFTER path validation).

Common situations: Mixing 'skip before capture' optimization with TraceApiBlock-style blocking interceptor semantics in one interceptor class; copying @IgnoreMethod from an after method onto a block-type before method.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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