{"record":{"id":"e68a4ad62d32034f","repo":"pinpoint-apm/pinpoint","slug":"already-closed-e68a4a","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/ChildTrace.java","lineNumber":177,"sourceCode":"    }\n\n\n    @Override\n    public boolean isClosed() {\n        return closed;\n    }\n\n    @Override\n    public void close() {\n        if (asyncTraceBlock) {\n            traceBlockEnd(ASYNC_BEGIN_STACK_ID);\n        }\n        close0();\n    }\n\n    public void close0() {\n        if (closed) {\n            logger.warn(\"Already closed {}\", this);\n            return;\n        }\n        closed = true;\n\n        if (!callStack.empty()) {\n            if (logger.isWarnEnabled()) {\n                stackDump(\"not empty call stack\");\n            }\n            // skip\n        } else {\n            logSpan();\n        }\n        this.wrappedSpanEventRecorder.close();\n        this.storage.close();\n    }\n\n    @Override\n    public TraceId getTraceId() {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/ChildTrace.java#L159-L195","documentation":"ChildTrace.close0() logs 'Already closed {}' as a warning when close0() is invoked on a ChildTrace instance whose `closed` flag is already true. ChildTrace is a lightweight per-span trace object, and the library guards against double-close so the underlying TraceRoot is not finalized twice. The warning means some code path closed the trace more than once; the second close is a no-op.","triggerScenarios":"Calling close() (which delegates to close0()) twice on the same ChildTrace, e.g. manual close() followed by framework/agent-triggered cleanup, or a finally-block close after the agent already closed the trace when the call stack was force-completed.","commonSituations":"Plugin/interceptor code that explicitly closes traces plus an agent-side cleanup path both firing; async trace completion racing with synchronous close; reusing a Trace reference after its lifecycle ended.","solutions":["Remove redundant close() calls from application/plugin code and let the agent manage the trace lifecycle","Guard your own cleanup with an idempotency check (e.g. a local AtomicBoolean) before calling close()","Ensure each Trace obtained from TraceContext is closed exactly once per request thread","If seen after upgrading, check the agent version for known double-close bugs in async trace handling"],"exampleFix":"// before\nTrace trace = traceContext.newTraceObject();\ndoWork();\ntrace.close();\ntrace.close(); // warns Already closed\n// after\nTrace trace = traceContext.newTraceObject();\ndoWork();\ntrace.close();","handlingStrategy":"try-catch","validationCode":"// check before cleanup\nif (trace != null && !isTraceClosed(trace)) {\n    trace.close();\n}","typeGuard":"boolean isOpen(Trace t) { return t != null && !isClosedFlagSet(t); }","tryCatchPattern":"try { trace.close(); } catch (RuntimeException e) { logger.debug(\"trace close skipped\", e); }","preventionTips":["Give one component sole ownership of trace close()","Use try/finally so close happens exactly once per request","Never reuse a Trace object after close()","Log at debug level in your own double-close guards"],"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"}