{"record":{"id":"40d45b168cd69a2c","repo":"pinpoint-apm/pinpoint","slug":"already-closed-40d45b","errorCode":null,"errorMessage":"Already closed {}","messagePattern":"Already closed (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java","lineNumber":183,"sourceCode":"        if (spanEvent.isTimeRecording()) {\n            spanEvent.markAfterTime();\n        }\n        logSpan(spanEvent);\n        // state restore\n        final SpanEvent previous = callStack.peek();\n        wrappedSpanEventRecorder(wrappedSpanEventRecorder, previous);\n    }\n\n\n    @Override\n    public boolean isClosed() {\n        return closed;\n    }\n\n    @Override\n    public void close() {\n        if (closed) {\n            logger.warn(\"Already closed {}\", this);\n            return;\n        }\n        closed = true;\n\n        final long afterTime = System.currentTimeMillis();\n        if (!callStack.empty()) {\n            if (logger.isWarnEnabled()) {\n                stackDump(\"not empty call stack\");\n            }\n            // skip\n        } else {\n            if (span.isTimeRecording()) {\n                span.markAfterTime(afterTime);\n            }\n            logSpan();\n        }\n\n        this.wrappedSpanEventRecorder.close();","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/DefaultTrace.java#L165-L201","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call close() exactly once per Trace; move cleanup into a single owner (e.g. one finally block)","Add an idempotency guard in your code before closing","Audit async code paths so only the thread that completes the request closes the trace","Check agent version/release notes for duplicate-close fixes in trace lifecycle handling"],"exampleFix":"// before\nfinally {\n    trace.close();\n}\n// ... elsewhere\ntrace.close(); // warns Already closed\n// after\nif (!trace.isClosed()) { // if API available, or track locally\n    trace.close();\n}","handlingStrategy":"type-guard","validationCode":"if (!trace.isClosed()) { trace.close(); }","typeGuard":"boolean needsClose(Trace t) { return t != null && !t.isClosed(); }","tryCatchPattern":"try { trace.close(); } catch (RuntimeException e) { logger.debug(\"already closed\", e); }","preventionTips":["Close each Trace exactly once, from a single owner","Avoid defensive duplicate close() calls in nested layers","For async flows, close on the thread that completes the request","Track closed state locally when the API lacks isClosed()"],"tags":["java","trace-lifecycle","double-close","pinpoint-profiler"],"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-17T15:17:12.973Z"}