{"record":{"id":"2ba28ec3f774c5e2","repo":"pinpoint-apm/pinpoint","slug":"cannot-stop-agent-current-status","errorCode":null,"errorMessage":"Cannot stop agent. Current status = [{}]","messagePattern":"Cannot stop agent\\. Current status = \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java","lineNumber":267,"sourceCode":"                public void run() {\n                    logger.info(\"stop() started. threadName:\" + Thread.currentThread().getName());\n                    DefaultAgent.this.close();\n                }\n            });\n\n            shutdownHookRegister.register(shutdownThread);\n\n        }\n\n    }\n\n    @Override\n    public void close() {\n        synchronized (agentStatusLock) {\n            if (this.agentStatus == AgentStatus.RUNNING) {\n                changeStatus(AgentStatus.STOPPED);\n            } else {\n                logger.warn(\"Cannot stop agent. Current status = [{}]\", this.agentStatus);\n                return;\n            }\n        }\n        logger.info(\"Stopping pinpoint Agent.\");\n        this.applicationContext.close();\n\n        // for testcase\n        if (agentOption.isStaticResourceCleanup()) {\n            this.loggingSystem.close();\n        }\n    }\n\n}\n","sourceCodeStart":249,"sourceCodeEnd":281,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/DefaultAgent.java#L249-L281","documentation":"WARN log from DefaultAgent.close() when the agent is not in the RUNNING state, so it cannot transition to STOPPED and close() returns without releasing resources. The parameter {} is the current AgentStatus (e.g. INITIALIZING, STOPPED). applicationContext.close() is skipped, which can leave background threads alive if callers assume shutdown happened.","triggerScenarios":"Calling close() before start() (status INITIALIZING), calling close() twice (second call sees STOPPED), or closing during a failed startup that never reached RUNNING.","commonSituations":"Shutdown hooks racing each other and both calling close(); cleanup code in tests tearing down an agent that failed to start; double-close in application stop sequences.","solutions":["Call close() only when getStatus() == AgentStatus.RUNNING; check status first.","Make shutdown idempotent on your side with a boolean/closed flag so close() runs once.","If the agent never started, do not call close(); dispose of the instance differently or fix the startup failure first.","Ensure only one shutdown hook owns the agent lifecycle."],"exampleFix":"// before\nruntime.addShutdownHook(new Thread(() -> agent.close()));\nagent.close(); // warn: Cannot stop agent. Current status = [STOPPED]\n\n// after\nprivate final AtomicBoolean closed = new AtomicBoolean(false);\nvoid shutdown() {\n    if (closed.compareAndSet(false, true) && agent.getStatus() == AgentStatus.RUNNING) {\n        agent.close();\n    }\n}","handlingStrategy":"type-guard","validationCode":"boolean canStop = (agent.getStatus() == AgentStatus.RUNNING);\nif (canStop) agent.close();","typeGuard":"boolean isClosable(DefaultAgent a) { return a.getStatus() == AgentStatus.RUNNING; }","tryCatchPattern":"try {\n    if (agent.getStatus() == AgentStatus.RUNNING) agent.close();\n} catch (Exception e) {\n    log.warn(\"agent shutdown failed\", e); // don't rethrow from shutdown hooks\n}","preventionTips":["Register exactly one shutdown hook that closes the agent.","Make your teardown idempotent (compareAndSet flag) for double-close safety.","Fix startup failures so the agent actually reaches RUNNING before cleanup runs."],"tags":["lifecycle","shutdown","double-close","agent"],"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"}