Skip to content

ShellSession times out when stdout has no trailing newline and the done marker is appended to the same line #36696

@nu1lx

Description

@nu1lx

Checked other resources

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

Reproduction Steps / Example Code (Python)

import tempfile
from pathlib import Path

from langchain.agents.middleware._execution import HostExecutionPolicy
from langchain.agents.middleware.shell_tool import ShellSession

policy = HostExecutionPolicy(command_timeout=0.5)
session = ShellSession(
    workspace=Path(tempfile.mkdtemp(prefix="lc-shell-repro-")),
    policy=policy,
    command=("/bin/bash",),
    environment={},
)

session.start()
try:
    result = session.execute("printf 'hello without newline'", timeout=policy.command_timeout)
    print(result)
finally:
    session.stop(1.0)

Error Message and Stack Trace (if applicable)

There is no Python exception. The bug is behavioral.

Expected:
CommandExecutionResult(output='hello without newline', exit_code=0, timed_out=False, ...)

Actual on current `master` before the fix:
CommandExecutionResult(output='', exit_code=None, timed_out=True, ...)

Description

ShellSession.execute() currently injects a completion marker into stdout using a separate printf call, and _collect_output() only recognizes command completion when a stdout line starts with that marker.

However, stdout is read with readline(). If the command output does not end with a trailing newline, the command's final stdout bytes and the injected done marker are returned as a single line, for example:

hello without newline__LC_SHELL_DONE__<id> 0

In that case, the current logic:

if source == "stdout" and data.startswith(marker):

misses the marker because it no longer appears at the start of the line. The command is then treated as still running until command_timeout is reached.

This affects minimal cases such as printf 'hello without newline' and can also affect file reads where the file does not end with a newline.

A minimal fix is to detect the marker anywhere in the stdout line, preserve any real stdout content that appears before it, and still parse the exit code from the marker suffix.

System Info

System Information
------------------
> OS:  Linux
> OS Version:  #1 SMP Fri Mar  6 10:10:19 UTC 2026
> Python Version:  3.13.12 (main, Feb 12 2026, 00:43:56) [Clang 21.1.4 ]

Package Information
-------------------
> langchain_core: 1.3.0a1
> langchain: 1.2.15
> langsmith: 0.6.3
> langchain_openai: 1.1.12
> langchain_tests: 1.1.6
> langgraph_sdk: 0.3.3

Optional packages not installed
-------------------------------
> deepagents
> deepagents-cli

Other Dependencies
------------------
> httpx: 0.28.1
> jsonpatch: 1.33
> langgraph: 1.1.5
> numpy: 2.3.4
> openai: 2.26.0
> orjson: 3.11.6
> packaging: 24.2
> pydantic: 2.12.5
> pytest: 9.0.2
> pytest-asyncio: 1.3.0
> pytest-benchmark: 5.2.3
> pytest-codspeed: 4.2.0
> pytest-recording: 0.13.4
> pytest-socket: 0.7.0
> pyyaml: 6.0.3
> requests: 2.33.0
> requests-toolbelt: 1.0.0
> rich: 14.2.0
> syrupy: 5.1.0
> tenacity: 9.1.2
> tiktoken: 0.12.0
> typing-extensions: 4.15.0
> uuid-utils: 0.12.0
> vcrpy: 8.1.1
> zstandard: 0.25.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions