alibaba/spring-ai-alibaba · error · IllegalStateException

Shell session is not running

Error message

Shell session is not running

What it means

ShellSession.execute() first checks that the underlying process is non-null and alive; if the shell process has exited or was never started, it throws this IllegalStateException instead of writing to a dead process's stdin. It is the guard that keeps command execution tied to a live shell.

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/ShellSessionManager.java:471

			try {
				if (!process.waitFor(timeoutMs, TimeUnit.MILLISECONDS)) {
					process.destroyForcibly();
				}
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
				process.destroyForcibly();
			}

			try {
				stdin.close();
			} catch (IOException e) {
				log.debug("Failed to close stdin", e);
			}
		}

		synchronized CommandResult execute(String command, long timeoutMs, int maxOutputLines, Long maxOutputBytes) {
			if (process == null || !process.isAlive()) {
				throw new IllegalStateException("Shell session is not running");
			}

			String marker = DONE_MARKER_PREFIX + UUID.randomUUID().toString().replace("-", "");
			long deadline = System.currentTimeMillis() + timeoutMs;

			try {
				// Clear output queue
				outputQueue.clear();

				// Send command
				stdin.write(command);
				if (!command.endsWith("\n")) {
					stdin.write("\n");
				}
				
				// Send marker command based on shell type
				if (isPowerShell) {
					// PowerShell only sets $LASTEXITCODE for native programs and scripts. Capture

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Catch IllegalStateException and call session.restart() (or manager.initialize()) to obtain a live process before retrying the command.
  2. Check session/process liveness (isAlive) before each execute() and recover proactively.
  3. Avoid running commands that can terminate the shell itself; run them detached (e.g. 'nohup ... &' or a subshell) if needed.
  4. Ensure no concurrent thread calls stop()/cleanup() while other threads are executing commands (synchronize at the application level).

Example fix

// before
CommandResult r = session.execute(cmd, timeout, maxLines, maxBytes); // throws if process died

// after
if (session == null || !session.isAlive()) { session.restart(); }
CommandResult r = session.execute(cmd, timeout, maxLines, maxBytes);
Defensive patterns

Strategy: try-catch

Validate before calling

// Liveness check before executing:
if (session == null || !session.isAlive()) session.restart();

Type guard

boolean sessionAlive(ShellSession s) { return s != null && s.isAlive(); }

Try / catch

try {
    result = session.execute(cmd, timeout, maxLines, maxBytes);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("not running")) {
        session.restart();
        result = session.execute(cmd, timeout, maxLines, maxBytes);
    }
}

Prevention

When it happens

Trigger: Calling session.execute(command, ...) (directly or via executeCommand/startup commands) after the shell process died (e.g. a previous command called 'exit'), after stop()/restart() tore it down, or on a session object whose process was never started.

Common situations: The executed command itself terminated the shell ('exit', fatal crash, OOM kill); a long idle period where the OS reaped the process; concurrent stop() from another thread; using a stale session reference recovered from a registry after the process died.

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


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/08f3738851c01b6b. Report an issue: GitHub.