langchain-ai/deepagents · error · RuntimeError
Textual's LinuxDriver no longer stores its output stream in
Error message
Textual's LinuxDriver no longer stores its output stream in `_file`, so the stderr guard cannot route the TUI to stdout. Update stdout_driver_class for the new internals.
What it means
TerminalStderrGuard patches Textual's LinuxDriver to capture its output stream and route the TUI to stdout when stderr is being used. The guard checks for the `_file` attribute inside LinuxDriver.__init__; if a Textual upgrade removed/renamed it, the patched driver raises RuntimeError rather than assigning a dead attribute and leaving a black screen.
Source
Thrown at libs/code/deepagents_code/_terminal_stderr.py:96
def __init__(
self,
app: App,
*,
debug: bool = False,
mouse: bool = True,
size: tuple[int, int] | None = None,
) -> None:
super().__init__(app, debug=debug, mouse=mouse, size=size)
if not hasattr(self, "_file"):
# Textual moved its output stream. Fail loudly while the
# caller's `finally` can still restore fd 2 to report it —
# assigning a dead attribute would leave a black screen.
msg = (
"Textual's LinuxDriver no longer stores its output stream "
"in `_file`, so the stderr guard cannot route the TUI to "
"stdout. Update stdout_driver_class for the new internals."
)
raise RuntimeError(msg)
self._file = stdout
return StdoutLinuxDriver
class TerminalStderrGuard:
"""Suppress native stderr writes while the TUI owns the terminal."""
def __init__(self, *, enabled: bool = False) -> None:
self._enabled = enabled
self._saved_stderr: int | None = None
self._closed = False
self._lock = threading.Lock()
@classmethod
def install(cls) -> TerminalStderrGuard:
"""Install suppression when stdout and stderr share a macOS terminal.
View on GitHub (pinned to a1af029e6e)
Solutions
- Pin Textual to the version range supported by deepagents-code (downgrade, e.g. `uv pip install 'textual==<pinned-version>'`, or regenerate the lockfile).
- Update `stdout_driver_class` in deepagents_code/_terminal_stderr.py to attach to the new Textual internals (whatever replaced `_file`, e.g. the new output/stream attribute).
- Report/track the incompatibility upstream so the guard is updated for the new Textual release.
Example fix
# before (patched driver, old internals)
if not hasattr(self, "_file"):
raise RuntimeError("Textual's LinuxDriver no longer stores its output stream in `_file` ...")
# after
attr = "_file" if hasattr(self, "_file") else "_output" # new Textual internals
setattr(self, attr, stdout) Defensive patterns
Strategy: fallback
Validate before calling
import textual, inspect
from textual.driver import Driver
def textual_compat() -> bool:
src = inspect.getsource(Driver.__init__) if hasattr(Driver, "__init__") else ""
# probe the patched driver type at import time
from deepagents_code._terminal_stderr import StdoutLinuxDriver
return "_file" in getattr(StdoutLinuxDriver, "__mro__", ()) and textual.VERSION.major_minor_ok # simplify: check pinned range
Type guard
def supports_stderr_guard(driver_cls) -> bool:
import inspect
return "_file" in inspect.getsource(driver_cls.__init__) Try / catch
try:
app.run()
except RuntimeError as exc:
if "LinuxDriver" in str(exc):
pin_supported_textual_version() # e.g. subprocess: pip install textual==<pin>
else:
raise Prevention
- Pin the Textual version in your lockfile and only upgrade together with deepagents-code.
- Run a smoke test that launches the TUI in CI after any dependency bump.
- Read Textual's driver changelog before upgrading major/minor versions.
When it happens
Trigger: Launching the deepagents-code TUI (StdoutLinuxDriver.__init__ path) with an installed Textual version whose LinuxDriver no longer stores its output stream in self._file. The check is invoked during driver construction.
Common situations: Upgrading Textual (e.g. a dependency bump pulled a newer Textual with refactored driver/output internals) while deepagents-code pins or assumes older internals; using a Textual pre-release/dev version.
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/303dcbb67a954936.
Report an issue: GitHub.