langchain-ai/deepagents · error · RuntimeError
UnixSocketEventSource.serve_forever called before start()
Error message
UnixSocketEventSource.serve_forever called before start()
What it means
`serve_forever()` awaits the internal asyncio server created by `start()`. If `start()` was never called — or failed before creating the server — there is nothing to await, so the method raises this RuntimeError, documented as a strict start-before-serve contract.
Source
Thrown at libs/code/deepagents_code/event_bus.py:193
# umask (different libc, mocked socket layer), force-tighten the mode.
with contextlib.suppress(OSError):
self.path.chmod(0o600)
logger.debug("External event listener bound at %s", self.path)
async def serve_forever(self) -> None:
"""Park until the underlying server is cancelled or fails.
`asyncio.start_unix_server` already begins accepting connections,
so this delegates to the server's own `serve_forever`. A fatal
error inside the accept loop propagates here, letting the
lifecycle owner notice and react.
Raises:
RuntimeError: If invoked before `start()`.
"""
if self._server is None:
msg = "UnixSocketEventSource.serve_forever called before start()"
raise RuntimeError(msg)
await self._server.serve_forever()
async def stop(self) -> None:
"""Close the listener and remove the socket path.
Idempotent: safe to call after a failed or never-started `start()`.
"""
server = self._server
self._server = None
if server is not None:
server.close()
with contextlib.suppress(Exception):
await server.wait_closed()
try:
_unlink_existing_socket(self.path)
except FileNotFoundError:
pass
except FileExistsError as exc:View on GitHub (pinned to a1af029e6e)
Solutions
- Call `await source.start()` before `serve_forever()` — start binds the socket and creates the server.
- Ensure a failed `start()` is not silently swallowed; abort startup instead of proceeding to serve.
- Restructure startup so `serve_forever` runs only in a task spawned after a confirmed successful `start()`.
Example fix
// before src = UnixSocketEventSource(path, sink) await src.serve_forever() # RuntimeError // after src = UnixSocketEventSource(path, sink) await src.start() await src.serve_forever()
Defensive patterns
Strategy: try-catch
Validate before calling
if getattr(source, "_server", None) is None:
await source.start()
await source.serve_forever() Type guard
def is_ready_to_serve(source) -> bool:
return getattr(source, "_server", None) is not None Try / catch
try:
await source.serve_forever()
except RuntimeError as exc:
if "called before start" in str(exc):
await source.start()
await source.serve_forever()
else:
raise Prevention
- Always pair construction with `await start()` before spawning a serve task.
- Let failures from `start()` propagate instead of continuing to serve.
- Spawn the serve task only after start() returns successfully.
When it happens
Trigger: Calling `await source.serve_forever()` directly after constructing `UnixSocketEventSource` without first calling `await source.start()`; also when a prior `start()` raised (e.g. bind failure) leaving `_server` as None.
Common situations: Copy-pasted serve loops from other asyncio servers that create the server inside `serve_forever`; background tasks launched before initialization completes; a swallowed exception from `start()` letting execution continue to the serve call.
Related errors
- UnixSocketEventSource is already started
- Refusing to remove non-socket external event path: {path}
- Server process is not running
- A workspace is required to start the remote agent.
- Session start stopped by hook
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/9bc9138124ace41d.
Report an issue: GitHub.