alibaba/spring-ai-alibaba · error · IllegalStateException
Shell session not initialized. Call initialize() before exec
Error message
Shell session not initialized. Call initialize() before executeCommand() or ensure lifecycle management (e.g., ShellToolAgentHook) is installed.
What it means
executeCommand() requires an initialized shell session, looked up in the run context and the global registry. If neither holds a session for the threadId and there is no saved config to recover from (HITL resume scenario), it throws this IllegalStateException telling you to call initialize() first or install lifecycle management. It prevents executing commands on a session that was never created.
Source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java:270
*/
public CommandResult executeCommand(String command, RunnableConfig config) {
ShellSession session = (ShellSession) config.context().get(SESSION_INSTANCE_CONTEXT_KEY);
if (session == null) {
// Try to recover from global registry using threadId
session = recoverSessionFromRegistry(config);
if (session == null) {
// Only auto-initialize in the HITL recovery case (threadId present).
// For truly uninitialized usage (no threadId), preserve the previous
// behavior and fail fast rather than starting a new shell process
// without lifecycle management.
if (config.threadId().isPresent()) {
log.warn("Shell session not found in context or registry for threadId {}. " +
"Creating new session for HITL recovery.", config.threadId().get());
initialize(config);
session = (ShellSession) config.context().get(SESSION_INSTANCE_CONTEXT_KEY);
}
else {
throw new IllegalStateException(
"Shell session not initialized. Call initialize() before executeCommand() " +
"or ensure lifecycle management (e.g., ShellToolAgentHook) is installed.");
}
}
}
log.info("Executing shell command: {}", command);
CommandResult result = session.execute(command, commandTimeout, maxOutputLines, maxOutputBytes);
// Apply redactions and track matches
String output = result.getOutput();
Map<String, List<String>> allMatches = new HashMap<>();
for (RedactionRule rule : redactionRules) {
RedactionResult redactionResult = rule.applyWithMatches(output);
output = redactionResult.getRedactedContent();
if (!redactionResult.getMatches().isEmpty()) {
allMatches.computeIfAbsent(rule.getPiiType(), k -> new ArrayList<>())View on GitHub (pinned to f82da0b50f)
Solutions
- Install the lifecycle hook (e.g. ShellToolAgentHook) so beforeAgent automatically calls initialize() before the tool runs.
- Explicitly call ShellSessionManager.initialize(config) before the first executeCommand() call.
- Verify the same context (holding SESSION_INSTANCE_CONTEXT_KEY) and threadId used at initialize() are passed to the tool call.
- Catch IllegalStateException and recover by calling initialize() then retrying the command once.
Example fix
// before
ShellTool tool = new ShellTool(manager);
agent.run("run tests"); // manager.initialize() never called -> IllegalStateException
// after
manager.initialize(config); // or register ShellToolAgentHook on the agent
ShellTool tool = new ShellTool(manager);
agent.run("run tests"); Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling the tool, confirm a session exists:
Object session = config.context().get("SHELL_SESSION_KEY");
if (session == null) manager.initialize(config); // ensure initialized before executeCommand Type guard
boolean hasSession(ShellSessionManager mgr, RunConfig cfg) {
return cfg.context().get("SHELL_SESSION_KEY") != null;
} Try / catch
try {
result = shellTool.execute(request, toolCtx);
} catch (IllegalStateException e) {
if (e.getMessage().contains("not initialized")) {
manager.initialize(config); // recover, then retry once
}
} Prevention
- Install ShellToolAgentHook (or equivalent lifecycle hook) so initialize() runs in beforeAgent automatically.
- Never call executeCommand() on a fresh manager without a prior initialize().
- Reuse the same context and threadId between initialize() and tool execution.
- In tests, call initialize() in a @BeforeEach setup method.
When it happens
Trigger: Calling ShellTool/executeCommand() on a ShellSessionManager whose initialize() was never called for the current threadId, without a ShellToolAgentHook (or equivalent AgentHook) installed to auto-initialize, and with no context-stored session or registry entry to recover.
Common situations: Using ShellTool directly in a hand-rolled agent without the lifecycle hook; running the tool after the context was reset/cleared so the session key vanished; calling the tool from a new thread with a fresh threadId that never went through beforeAgent.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot create update map after mergeAll() has been called
- mergeAll() can only be called once
- Failed to initialize shell session
- Shell session not initialized. Cannot restart a session that
- Shell session is not running
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/59b14d8736aa45eb.
Report an issue: GitHub.