alibaba/spring-ai-alibaba · warning
Shutdown command failed: {}
Error message
Shutdown command failed: {} What it means
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.
Source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java:166
/**
* Clean up shell session.
* This removes the session from both the context and the global registry.
*/
public void cleanup(RunnableConfig config) {
try {
// Try to get session from context first, then from registry
ShellSession session = (ShellSession) config.context().get(SESSION_INSTANCE_CONTEXT_KEY);
if (session == null) {
session = getSessionFromRegistry(config);
}
if (session != null) {
// Run shutdown commands
for (String command : shutdownCommands) {
try {
session.execute(command, commandTimeout, maxOutputLines, maxOutputBytes);
} catch (Exception e) {
log.warn("Shutdown command failed: {}", command, e);
}
}
}
} finally {
doCleanup(config);
}
}
private void doCleanup(RunnableConfig config) {
// Try to get session from context first
ShellSession session = (ShellSession) config.context().get(SESSION_INSTANCE_CONTEXT_KEY);
Path tempDir = (Path) config.context().get(SESSION_PATH_CONTEXT_KEY);
// If not in context, try to get from registry (HITL resume scenario)
SessionEntry registryEntry = null;
if (session == null && config.threadId().isPresent()) {
registryEntry = SESSION_REGISTRY.remove(config.threadId().get());
if (registryEntry != null) {View on GitHub (pinned to f82da0b50f)
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.
Example fix
// before
shutdownCommands = List.of("exit", "sync"); // 'sync' runs after shell died
// after
shutdownCommands = List.of("sync", "exit"); Defensive patterns
Strategy: try-catch
Validate before calling
if (shutdownCommands != null) {
for (int i = 0; i < shutdownCommands.size(); i++) {
if ("exit".equalsIgnoreCase(shutdownCommands.get(i).trim()) && i < shutdownCommands.size() - 1) {
log.warn("'exit' is not the last shutdown command; later commands will fail");
}
}
} Try / catch
try {
session.execute(cmd, commandTimeout, maxOutputLines, maxOutputBytes);
} catch (Exception e) {
log.warn("Shutdown command failed: {}", cmd, e); // safe to ignore: session is being torn down
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Startup command failed:
- Command timed out, restarting session
- Failed to initialize shell session
- Model call failed, maximum number of retries reached:${excep
- Failed to initialize shell session
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/2733add119792aee.
Report an issue: GitHub.