pinpoint-apm/pinpoint · warning

Duplicated {} scope={}

Error message

Duplicated {} scope={}

What it means

WARN from AsyncScopeUtils.nested() when trace.addScope(scopeName) returns a non-null old scope, meaning an async scope with the same name already exists on this trace — the async trace block was entered re-entrantly or the scope was leaked by a previous unmatched begin/end. The code treats this as nesting and returns true so the caller can skip re-initialization; a commented-out deleteAsyncTrace indicates the old corrupted-trace cleanup is disabled, so the trace may carry stale state.

Source

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

package com.navercorp.pinpoint.profiler.context;

import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.scope.TraceScope;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public final class AsyncScopeUtils {
    private static final Logger logger = LogManager.getLogger(AsyncScopeUtils.class);

    private AsyncScopeUtils() {
    }

    public static boolean nested(Trace trace, String scopeName) {
        // add async scope.
        final TraceScope oldScope = trace.addScope(scopeName);
        if (oldScope != null) {
            if (logger.isWarnEnabled()) {
                logger.warn("Duplicated {} scope={}", trace.getClass().getSimpleName(), oldScope.getName());
            }
            // delete corrupted trace.
//            deleteAsyncTrace(trace);
            return true;
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("start {} scope", trace.getClass().getSimpleName());
            }
        }
        return false;
    }
}

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Ensure every async trace block begin has exactly one matching end on the same trace.
  2. Use a unique scope name per logical async unit instead of a shared constant across re-entrant calls.
  3. Do not reuse a single Trace across concurrent async continuations; each continuation should get its own async trace.
  4. If you see this repeatedly, check the installed plugin versions for known double-entry bugs and upgrade the agent.

Example fix

// before
AsyncScopeUtils.nested(trace, "MY_ASYNC"); // called again for same trace

// after
if (AsyncScopeUtils.nested(trace, "MY_ASYNC")) {
    return; // skip duplicate scope entry
}
Defensive patterns

Strategy: validation

Validate before calling

// before entering an async scope, ensure it is not already active
final TraceScope scope = trace.getScope(scopeName);
if (scope != null) {
    // scope already exists; skip addScope / nested entry
}

Prevention

When it happens

Trigger: Entering the same async scope twice on one trace: e.g. calling the async trace begin API twice without a matching end, or async callbacks sharing a single Trace object concurrently.

Common situations: Async instrumentation (CompletableFuture/executor plugins) where a callback is executed twice or a span event's traceBlockEnd is missed; custom plugins reusing one scope name per trace.

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/3206be156703e9e9. Report an issue: GitHub.