{"record":{"id":"2733add119792aee","repo":"alibaba/spring-ai-alibaba","slug":"shutdown-command-failed","errorCode":null,"errorMessage":"Shutdown command failed: {}","messagePattern":"Shutdown command failed: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java","lineNumber":166,"sourceCode":"\n\t/**\n\t * Clean up shell session.\n\t * This removes the session from both the context and the global registry.\n\t */\n\tpublic void cleanup(RunnableConfig config) {\n\t\ttry {\n\t\t\t// Try to get session from context first, then from registry\n\t\t\tShellSession session = (ShellSession) config.context().get(SESSION_INSTANCE_CONTEXT_KEY);\n\t\t\tif (session == null) {\n\t\t\t\tsession = getSessionFromRegistry(config);\n\t\t\t}\n\t\t\tif (session != null) {\n\t\t\t\t// Run shutdown commands\n\t\t\t\tfor (String command : shutdownCommands) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsession.execute(command, commandTimeout, maxOutputLines, maxOutputBytes);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\tlog.warn(\"Shutdown command failed: {}\", command, e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tdoCleanup(config);\n\t\t}\n\t}\n\n\tprivate void doCleanup(RunnableConfig config) {\n\t\t// Try to get session from context first\n\t\tShellSession session = (ShellSession) config.context().get(SESSION_INSTANCE_CONTEXT_KEY);\n\t\tPath tempDir = (Path) config.context().get(SESSION_PATH_CONTEXT_KEY);\n\n\t\t// If not in context, try to get from registry (HITL resume scenario)\n\t\tSessionEntry registryEntry = null;\n\t\tif (session == null && config.threadId().isPresent()) {\n\t\t\tregistryEntry = SESSION_REGISTRY.remove(config.threadId().get());\n\t\t\tif (registryEntry != null) {","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java#L148-L184","documentation":"ShellSessionManager.cleanup runs configured shutdown commands (e.g. 'exit') through the still-open shell session before tearing it down. If any single shutdown command throws while executing, this warning is logged with the command and exception, and the loop continues to the next command; doCleanup then runs in the finally block regardless. Session teardown is never skipped because of a failed shutdown command.","triggerScenarios":"cleanup's session.execute(command, commandTimeout, maxOutputLines, maxOutputBytes) throws for a shutdown command — typically because the shell already exited (e.g. an earlier 'exit' terminated it), the command timed out, or the session's streams are broken.","commonSituations":"1) shutdownCommands containing 'exit' followed by another command, so the second command executes on a dead shell. 2) The child process crashed or was killed before cleanup. 3 commandTimeout too short for a slow teardown script. 4 Tests/agents closing sessions concurrently, racing the cleanup.","solutions":["Order shutdownCommands so terminating commands ('exit') come last, or drop redundant exits.","Increase commandTimeout if the shutdown script legitimately needs longer.","Treat the warning as benign when it stems from an already-exited shell, or filter that case before executing.","Ensure only one component owns session lifecycle to avoid concurrent cleanup."],"exampleFix":"// before\nshutdownCommands = List.of(\"exit\", \"sync\"); // 'sync' runs after shell died\n// after\nshutdownCommands = List.of(\"sync\", \"exit\");","handlingStrategy":"try-catch","validationCode":"if (shutdownCommands != null) {\n    for (int i = 0; i < shutdownCommands.size(); i++) {\n        if (\"exit\".equalsIgnoreCase(shutdownCommands.get(i).trim()) && i < shutdownCommands.size() - 1) {\n            log.warn(\"'exit' is not the last shutdown command; later commands will fail\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.execute(cmd, commandTimeout, maxOutputLines, maxOutputBytes);\n} catch (Exception e) {\n    log.warn(\"Shutdown command failed: {}\", cmd, e); // safe to ignore: session is being torn down\n}","preventionTips":["Put terminating commands like 'exit' last in shutdownCommands","Set a realistic commandTimeout for teardown scripts","Avoid sharing one ShellSessionManager across concurrent agents","Treat this warning as benign when the shell already exited"],"tags":["shell","session-cleanup","process-management","timeout"],"backgroundTag":"broken-pipe","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}