pinpoint-apm/pinpoint · warning

Already closed

Error message

Already closed {}

What it means

DefaultTrace.close() logs 'Already closed {}' when close() is called on a trace whose `closed` flag is already set. Close finalizes the span (afterTime, flushing remaining call stack); the guard prevents double-finalization. The warning indicates duplicate lifecycle termination of the same Trace.

Solutions

  1. Call close() exactly once per Trace; move cleanup into a single owner (e.g. one finally block)
  2. Add an idempotency guard in your code before closing
  3. Audit async code paths so only the thread that completes the request closes the trace
  4. Check agent version/release notes for duplicate-close fixes in trace lifecycle handling

Example fix

// before
finally {
    trace.close();
}
// ... elsewhere
trace.close(); // warns Already closed
// after
if (!trace.isClosed()) { // if API available, or track locally
    trace.close();
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!trace.isClosed()) { trace.close(); }

Type guard

boolean needsClose(Trace t) { return t != null && !t.isClosed(); }

Try / catch

try { trace.close(); } catch (RuntimeException e) { logger.debug("already closed", e); }

Prevention

When it happens

Trigger: Invoking close() twice on the same DefaultTrace, e.g. from both an application cleanup path and the agent's trace finalizer, or from a finally block plus a framework shutdown hook.

Common situations: Request-scoped cleanup code that closes traces defensively; async request handling where both the worker thread and continuation close the trace; misconfigured async trace factories reusing references.

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/40d45b168cd69a2c. Report an issue: GitHub.

Appendix: source

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

        if (spanEvent.isTimeRecording()) {
            spanEvent.markAfterTime();
        }
        logSpan(spanEvent);
        // state restore
        final SpanEvent previous = callStack.peek();
        wrappedSpanEventRecorder(wrappedSpanEventRecorder, previous);
    }


    @Override
    public boolean isClosed() {
        return closed;
    }

    @Override
    public void close() {
        if (closed) {
            logger.warn("Already closed {}", this);
            return;
        }
        closed = true;

        final long afterTime = System.currentTimeMillis();
        if (!callStack.empty()) {
            if (logger.isWarnEnabled()) {
                stackDump("not empty call stack");
            }
            // skip
        } else {
            if (span.isTimeRecording()) {
                span.markAfterTime(afterTime);
            }
            logSpan();
        }

        this.wrappedSpanEventRecorder.close();

View on GitHub (pinned to 744c3d3075)