FoundationAgents/OpenManus · warning · ToolError
Session has not started.
Error message
Session has not started.
What it means
Persistent bash tool session guard: stop() raises ToolError if _started is False, i.e. start() never spawned the bash process. stop() is meant to terminate a live shell; calling it on a session that was constructed but not started (or already stopped and never restarted) is a usage error.
Source
Thrown at app/tool/bash.py:50
if self._started:
return
self._process = await asyncio.create_subprocess_shell(
self.command,
preexec_fn=os.setsid,
shell=True,
bufsize=0,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
self._started = True
def stop(self):
"""Terminate the bash shell."""
if not self._started:
raise ToolError("Session has not started.")
if self._process.returncode is not None:
return
self._process.terminate()
async def run(self, command: str):
"""Execute a command in the bash shell."""
if not self._started:
raise ToolError("Session has not started.")
if self._process.returncode is not None:
return CLIResult(
system="tool must be restarted",
error=f"bash has exited with returncode {self._process.returncode}",
)
if self._timed_out:
raise ToolError(
f"timed out: bash has not returned in {self._timeout} seconds and must be restarted",
)
View on GitHub (pinned to 52a13f2a57)
Solutions
- Only call stop() after a successful start(): set a flag or assign the session only after await start() completes.
- In cleanup code, guard with the same condition the class uses: 'if session._started: session.stop()' — better, wrap stop() in try/except ToolError and ignore the not-started case.
- Structure setup as 'session = None; try: session = _BashSession(); await session.start() ... finally: if session ... stop()' so an unstarted session is never stopped.
Example fix
# before
session = _BashSession()
try:
await session.start()
...
finally:
session.stop() # ToolError if start() raised
# after
try:
session = _BashSession()
await session.start()
...
finally:
if session is not None and session._started:
session.stop() Defensive patterns
Strategy: validation
Validate before calling
if session._started:
session.stop() Type guard
def is_stoppable(s: _BashSession) -> bool:
return bool(s._started) and s._process is not None and s._process.returncode is None Try / catch
try:
session.stop()
except ToolError as e:
if 'Session has not started.' not in str(e):
raise # ignore the not-started case during cleanup Prevention
- Only reference the session after start() succeeds.
- In finally blocks, guard stop() with the started flag.
- Treat stop-before-start as a wiring bug; fix the ordering.
When it happens
Trigger: Constructing _BashSession and calling stop() without start(); calling stop() twice after an exception in start(); cleanup paths (finally blocks) that stop a session whose start() threw.
Common situations: try/finally cleanup where start() failed and finally still calls stop(); generic teardown code iterating over sessions that may be unstarted.
Related errors
- timed out: bash has not returned in {self._timeout} seconds
- no command provided.
- Failed to create sandbox: {e}
- Sandbox not initialized
- Session not initialized
AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15).
Data as JSON: /api/errors/1fdb11c5a334ce13.
Report an issue: GitHub.