pinpoint-apm/pinpoint · error · IllegalStateException

traceReference is null

Error message

traceReference is null

What it means

DisableAsyncContext.bind() throws IllegalStateException('traceReference is null') when binding an async trace into a Reference that already holds a non-null value (message is misleading). It enforces the invariant that the async trace slot is empty before binding.

Source

Thrown at agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DisableAsyncContext.java:65

    private Trace newAsyncContextTrace(Reference<Trace> reference) {
        final Trace asyncTrace = local.asyncTraceContext().continueDisableAsyncContextTraceObject(traceRoot);
        bind(reference, asyncTrace);

        if (logger.isDebugEnabled()) {
            logger.debug("asyncTraceContext.continueDisableAsyncContextTraceObject() AsyncTrace:{}", asyncTrace);
        }

        if (AsyncScopeUtils.nested(asyncTrace, ASYNC_TRACE_SCOPE)) {
            return null;
        }

        return asyncTrace;
    }

    private void bind(Reference<Trace> reference, Trace asyncTrace) {
        if (reference.get() != null) {
            throw new IllegalStateException("traceReference is null");
        }
        reference.set(asyncTrace);
    }

    @Override
    public Trace currentAsyncTraceObject() {
        final Reference<Trace> reference = local.binder().get();
        return reference.get();
    }

    @Override
    public void close() {
        local.binder().remove();
    }


    @Override
    public boolean finish() {

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Bind each async trace to a fresh Reference
  2. Close/complete the previous async trace before rebinding
  3. Check for duplicate newAsyncContextTrace calls
  4. Upgrade to a fixed pinpoint version

Example fix

// before
bind(reference, asyncTrace); // throws if reference already set
// after
if (reference.get() == null) {
    reference.set(asyncTrace);
} else {
    asyncTrace.close();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (reference.get() != null) {
    // already bound; do not bind again
}

Type guard

boolean canBind(Reference<Trace> ref) {
    return ref.get() == null;
}

Try / catch

try {
    disableAsyncContext.bind(reference, asyncTrace);
} catch (IllegalStateException e) {
    logger.warn("reference already bound in DisableAsyncContext", e);
}

Prevention

When it happens

Trigger: newAsyncContextTrace flow on DisableAsyncContext reaching bind(reference, asyncTrace) while reference.get() != null — the slot was already bound to another trace.

Common situations: Double-binding of async traces when sampling is disabled; lifecycle races reusing an already-bound reference; plugin code calling currentAsyncTraceObject repeatedly without closing traces.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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