{"record":{"id":"f394bf85f190c301","repo":"pinpoint-apm/pinpoint","slug":"cannot-leave-with-trace-scope-depth-depth","errorCode":null,"errorMessage":"cannot leave with trace scope. depth: ${depth}","messagePattern":"cannot leave with trace scope\\. depth: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/scope/BoundaryTraceScope.java","lineNumber":59,"sourceCode":"            return false;\n        } else {\n            depth++;\n            return true;\n        }\n    }\n\n    public boolean canLeave() {\n        if (skippedBoundary == 0 && depth == 1) {\n            return true;\n        } else {\n            skippedBoundary--;\n            return false;\n        }\n    }\n\n    public void leave() {\n        if (!isActive()) {\n            throw new IllegalStateException(\"cannot leave with trace scope. depth: \" + depth);\n        }\n\n        if (skippedBoundary != 0 || depth != 1) {\n            throw new IllegalStateException(\"cannot leave with BOUNDARY trace scope. depth: \" + depth);\n        }\n        depth--;\n    }\n\n    @Override\n    public boolean isActive() {\n        return depth > 0;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"DefaultTraceScope{\");\n        sb.append(\"name='\").append(name).append('\\'');\n        sb.append(\", depth=\").append(depth);","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/scope/BoundaryTraceScope.java#L41-L77","documentation":"BoundaryTraceScope.leave() throws IllegalStateException when the scope cannot be legally exited: either the scope is not active (depth <= 0) or nested boundary counting is inconsistent (skippedBoundary != 0 or depth != 1). Boundary scopes track nested entry/exit pairs for a trace; leave() is only valid when exactly one unmatched entry exists. The guard protects the profiler's scope invariant that pushes and pops are balanced.","triggerScenarios":"leave() is called without a matching push/enter (isActive() false), or called while nested boundary entries remain (depth != 1) or boundary skips are outstanding (skippedBoundary != 0) — typically unbalanced interceptor enter/exit, an exception thrown between push and leave, or double-leave on the same scope.","commonSituations":"Interceptors that call leave() in a path where push() never ran (e.g. an early return before push), exception thrown mid-interception skipping the balanced leave, or recursive instrumentation entering the boundary twice but leaving only once/incorrectly nested.","solutions":["Ensure every scope push/enter has exactly one matching leave in a finally block","Verify push() executes before any early return that later triggers leave()","Check for double-leave (leave called twice for one scope) in the interceptor chain","Review recursive/reentrant instrumented methods to ensure nested boundaries are balanced before leaving"],"exampleFix":"// before\nTraceScope scope = trace.getScope(SCOPE_NAME);\nif (scope != null) {\n    scope.leave();\n}\n// after\nTraceScope scope = trace.getScope(SCOPE_NAME);\nif (scope != null && scope.isActive()) {\n    try {\n        // instrumented work\n    } finally {\n        scope.leave();\n    }\n}","handlingStrategy":"try-catch","validationCode":"TraceScope scope = trace.getScope(SCOPE_NAME);\nif (scope == null || !scope.isActive()) {\n    return; // nothing to leave\n}","typeGuard":"boolean canLeaveSafely(TraceScope scope) {\n    return scope != null && scope.isActive();\n}","tryCatchPattern":"try {\n    scope.leave();\n} catch (IllegalStateException e) {\n    logger.warn(\"Unbalanced trace scope exit: {}\", e.getMessage());\n}","preventionTips":["Always pair scope push with leave inside try/finally","Never call leave() on a path where push() may not have executed","Watch for double instrumentation of reentrant methods causing nested scopes","Log scope depth around boundary operations while debugging interceptors"],"tags":["pinpoint-profiler","trace-scope","unbalanced-scope"],"backgroundTag":"invalid-state-transition","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}