pinpoint-apm/pinpoint · error · IllegalStateException

cannot leave with BOUNDARY trace scope. depth: ${depth}

Error message

cannot leave with BOUNDARY trace scope. depth: ${depth}

What it means

BoundaryTraceScope.leave() enforces the internal invariants of a BOUNDARY-scoped trace scope: the scope must be active, no boundary blocks may be skipped (skippedBoundary==0), and the depth must be exactly 1 when leaving. Thrown as IllegalStateException when the code attempts to leave a boundary scope that is unbalanced — i.e. an enter/leave pair mismatch.

Source

Thrown at agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/scope/BoundaryTraceScope.java:63

        }
    }

    public boolean canLeave() {
        if (skippedBoundary == 0 && depth == 1) {
            return true;
        } else {
            skippedBoundary--;
            return false;
        }
    }

    public void leave() {
        if (!isActive()) {
            throw new IllegalStateException("cannot leave with trace scope. depth: " + depth);
        }

        if (skippedBoundary != 0 || depth != 1) {
            throw new IllegalStateException("cannot leave with BOUNDARY trace scope. depth: " + depth);
        }
        depth--;
    }

    @Override
    public boolean isActive() {
        return depth > 0;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("DefaultTraceScope{");
        sb.append("name='").append(name).append('\'');
        sb.append(", depth=").append(depth);
        sb.append(", skippedBoundary=").append(skippedBoundary);
        sb.append('}');
        return sb.toString();
    }

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Ensure every enterBoundary() call has a matching leaveBoundary() in a finally block
  2. Check that skipEnterBoundary/leaveSkipBoundary pairs are balanced
  3. Verify the interceptor is not re-entering the same boundary scope before leaving it
  4. Log depth and skippedBoundary at enter/leave points to find the imbalance

Example fix

// before
trace.enterBoundary(1);
doWork();
trace.leaveBoundary(1);
// after
trace.enterBoundary(1);
try {
    doWork();
} finally {
    trace.leaveBoundary(1);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!scope.isActive() || scope.getDepth() != 1) { throw new IllegalStateException("boundary scope unbalanced before leave"); }

Try / catch

try { scope.leave(); } catch (IllegalStateException e) { logger.warn("unbalanced boundary scope: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling leave() when skippedBoundary != 0 (a boundary-skip counter was incremented by skipEnterBoundary without a matching leaveSkipBoundary) or when depth != 1 (multiple nested enters or leave called at the wrong nesting level).

Common situations: Custom trace instrumentation plugins that call enterBoundary/leaveBoundary unbalancedly (e.g. missing leave on an exception path), or re-entrancy where the interceptor enters the boundary twice but leaves once.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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