langchain - ✅(Solved) Fix InjectedState with a NotRequired state field raises KeyError when the field is absent from state [10 pull requests, 7 comments, 5 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#35585Fetched 2026-04-08 00:25:23
View on GitHub
Comments
7
Participants
5
Timeline
24
Reactions
0
Timeline (top)
cross-referenced ×10commented ×7labeled ×3referenced ×3

Description

When using InjectedState(<field>) on a tool parameter, and the referenced field is declared as NotRequired in the custom state schema, the ToolNode crashes with an unhandled KeyError if that field was never populated in the state.

We noticed this behaviour after upgrading to langchain >= 1.0.0. The same behaviour could not be reproduced with earlier versions.

Error Message

File ".../langgraph/prebuilt/tool_node.py", line 1358, in _inject_tool_args state[state_field] if state_field else state ~~~~~^^^^^^^^^^^^^ KeyError: 'city'

Root Cause

Description

When using InjectedState(<field>) on a tool parameter, and the referenced field is declared as NotRequired in the custom state schema, the ToolNode crashes with an unhandled KeyError if that field was never populated in the state.

We noticed this behaviour after upgrading to langchain >= 1.0.0. The same behaviour could not be reproduced with earlier versions.

Fix Action

Fix / Workaround

  • 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.

PR fix notes

PR #7039: fix: handle missing NotRequired state fields in InjectedState tool args

Description (problem / solution / changelog)

Problem

When a tool uses InjectedState("city") and city is declared as NotRequired in a custom state schema, ToolNode crashes with a KeyError if that field was never populated in state.

Fix

Changed state[state_field] to state.get(state_field) so missing optional fields safely return None instead of crashing.

Also added None as default to getattr(state, state_field, None) for the non-dict branch for consistency.

Related Issue

Fixes #35585

Changed files

  • libs/prebuilt/langgraph/prebuilt/tool_node.py (modified, +2/-2)

PR #35606: fix(langchain): handle NotRequired fields in InjectedState without KeyError

Description (problem / solution / changelog)

Fixes #35585 - InjectedState with NotRequired state field raises KeyError when field is absent.

This contribution was developed with AI assistance.

Problem

When a tool parameter annotated with InjectedState('<field>') references a NotRequired state field, the upstream ToolNode crashes with KeyError if that field hasn't been populated.

Solution

New ToolNode subclass (308 lines) in langchain.tools.tool_node that overrides _inject_tool_args with NotRequired-aware state access:

  • _get_not_required_fields() detects NotRequired fields via __optional_keys__, get_type_hints(), and stringified annotation inspection
  • Uses .get() for NotRequired fields (returns None) vs direct subscript for required fields
  • Handles total=True and total=False TypedDicts
  • create_agent() factory passes state_schema to the custom ToolNode

9 unit/integration tests (316 lines) covering absent fields, present fields, required fields still raising, full state injection, and mixed field scenarios.

Review areas

  1. ToolNode subclass re-implements _inject_tool_args - upstream langgraph changes could diverge
  2. Conservative fallback: no schema = all fields use .get()
  3. Stringified annotation detection for from __future__ import annotations

Changed files

  • libs/langchain_v1/langchain/agents/factory.py (modified, +7/-1)
  • libs/langchain_v1/langchain/tools/__init__.py (modified, +7/-1)
  • libs/langchain_v1/langchain/tools/tool_node.py (modified, +304/-4)
  • libs/langchain_v1/tests/unit_tests/agents/test_injected_state_not_required.py (added, +315/-0)
  • libs/langchain_v1/tests/unit_tests/tools/test_imports.py (modified, +1/-0)

PR #7048: fix(prebuilt): handle missing NotRequired state fields in InjectedState

Description (problem / solution / changelog)

Bug

When a tool parameter uses InjectedState("field") and the referenced field is declared as NotRequired in the custom state schema, ToolNode crashes with an unhandled KeyError if that field was never populated in the state.

Reported in: langchain-ai/langchain#35585

Root cause

In _inject_tool_args(), state field extraction uses direct dict access (state[state_field]) and bare getattr(state, state_field), both of which raise when the key/attribute is missing. This is correct for required fields but fails for NotRequired fields that may legitimately be absent.

Fix

  • Replace state[state_field] with state.get(state_field) for dict-based state
  • Replace getattr(state, state_field) with getattr(state, state_field, None) for object-based state

Missing fields now inject None instead of raising KeyError/AttributeError. Tools that declare their injected parameter as Optional[T] (matching the NotRequired state field) will receive None and can handle it gracefully.

Testing

  • Added test_tool_node_inject_state_not_required_missing: verifies that a tool with Annotated[str | None, InjectedState("city")] receives None when city is absent from state, and receives the value when present
  • Updated existing test_tool_node_inject_state to reflect new behavior (missing field = error response, not KeyError)
  • All 11 inject-related tests pass

Fixes langchain-ai/langchain#35585

Changed files

  • libs/prebuilt/langgraph/prebuilt/tool_node.py (modified, +3/-3)
  • libs/prebuilt/tests/test_tool_node.py (modified, +47/-2)

PR #35638: fix: InjectedState with a NotRequired state field raises KeyError w...

Description (problem / solution / changelog)

Summary

Fixes #35585.

What changed

<!-- Claude filled in the implementation details at commit time -->

Implemented a fix based on the issue description. See the diff for specifics.

Testing

  • Verified against the existing test suite
  • Checked that the fix addresses the reported behavior

Changed files

  • libs/langchain_v1/tests/unit_tests/agents/test_create_agent_tool_validation.py (modified, +93/-1)

PR #7067: Fix KeyError in ToolNode when InjectedState field is missing from state

Description (problem / solution / changelog)

Description

This PR fixes a KeyError that occurs when using InjectedState with a NotRequired state field that is absent from the current state.

In ToolNode._inject_tool_args, state values were being extracted using direct dictionary indexing (state[state_field]) or getattr(state, state_field). If the field was marked as NotRequired in the state schema and not present in the state, this would raise a KeyError or AttributeError.

The fix switches to .get() for dictionaries and getattr(..., None) for objects, ensuring that missing optional fields default to None instead of crashing the node.

Related Issues

Fixes https://github.com/langchain-ai/langchain/issues/35585

Checklist

  • Verified fix for dict-based state injection
  • Verified fix for object-based state injection
  • Syntax checked via py_compile

Changed files

  • libs/prebuilt/langgraph/prebuilt/tool_node.py (modified, +2/-2)

PR #35684: fix(langchain): handle NotRequired fields in InjectedState without KeyError

Description (problem / solution / changelog)

Summary

Fixes #35585.

When InjectedState("field") references a TypedDict field marked as NotRequired, the upstream langgraph.prebuilt.ToolNode._inject_tool_args method accesses state[field] directly — raising KeyError when that field is absent from the runtime state.

What changed

  • langchain/tools/tool_node.py — Introduced a ToolNode subclass that overrides _inject_tool_args to use .get() (for dict state) and getattr(…, None) (for object state), so missing optional fields resolve to None instead of crashing.
  • langchain/agents/factory.py — Updated create_agent to import and use the patched ToolNode from langchain.tools.tool_node rather than importing directly from langgraph.
  • tests/unit_tests/tools/test_tool_node.py — Added 4 tests covering:
    1. Normal injection when the field is present
    2. NotRequired field absent → returns None (the core regression)
    3. Full-state injection (no field specified)
    4. Missing attribute on non-dict state objects

Reproducer (from issue)

class CustomAgentState(AgentState):
    city: NotRequired[str]

@tool
def get_weather(city: Annotated[str, InjectedState("city")]) -> str:
    return f"Sunny in {city}"

Before this fix, invoking the tool when city was never set in state raised:

KeyError: 'city'

Testing

All 734 existing unit tests pass (tests/unit_tests/agents/ + tests/unit_tests/tools/), plus the 4 new tests.

Changed files

  • libs/langchain_v1/langchain/agents/factory.py (modified, +2/-1)
  • libs/langchain_v1/langchain/tools/tool_node.py (modified, +82/-1)
  • libs/langchain_v1/tests/unit_tests/tools/test_tool_node.py (added, +110/-0)

PR #7089: fix(prebuilt): tolerate absent NotRequired state fields in InjectedState

Description (problem / solution / changelog)

Problem

When a tool parameter is annotated with InjectedState("field") and that field is declared as NotRequired in the custom graph state schema, the ToolNode crashed with an unhandled KeyError if the field was not yet populated in the state dict:

File ".../langgraph/prebuilt/tool_node.py", line 1358, in _inject_tool_args
    state[state_field] if state_field else state
    ~~~~~^^^^^^^^^^^^^
KeyError: 'city'

Minimal reproduction:

from typing import Annotated
from typing_extensions import NotRequired
from langgraph.prebuilt import InjectedState
from langchain.agents import AgentState

class CustomAgentState(AgentState):
    city: NotRequired[str]  # Optional — may not be present in state

@tool
def get_weather(city: Annotated[str, InjectedState("city")]) -> str:
    return f"It's always sunny in {city}!"

If city is absent from the state (never set by the user), the ToolNode raises KeyError: 'city' instead of gracefully passing None.

Fix

Use state.get(state_field) instead of state[state_field] for the dict case, and getattr(state, state_field, None) instead of getattr(state, state_field) for the object case. Both return None when the field is absent, which is the correct sentinel for an optional / not-yet-populated state field.

Tools that require the field to be non-None will still fail at their own validation boundary, which gives a cleaner error than an internal KeyError.

Closes langchain-ai/langchain#35585

Changed files

  • libs/prebuilt/langgraph/prebuilt/tool_node.py (modified, +2/-2)

PR #7104: fix(langgraph): handle NotRequired fields in InjectedState

Description (problem / solution / changelog)

Description

This PR fixes a bug where InjectedState would raise a KeyError when trying to inject a NotRequired field that is not present in the state.

Problem

When using InjectedState(<field>) on a tool parameter, and the referenced field is declared as NotRequired in the custom state schema, the ToolNode crashes with an unhandled KeyError if that field was never populated in the state.

This behavior was introduced in langchain >= 1.0.0.

Solution

Changed the state field access in _inject_tool_args method to:

  • Use state.get(state_field) for dict-based states (returns None if key doesn't exist)
  • Use getattr(state, state_field, None) for object-based states (returns None if attribute doesn't exist)

This allows tools to receive None for missing NotRequired fields instead of crashing.

Testing

Added comprehensive test coverage:

  • test_tool_node_inject_state_not_required_field() - Tests dict-based state with NotRequired field
  • test_tool_node_inject_state_not_required_field_async() - Async version of the above
  • test_tool_node_inject_state_not_required_dataclass() - Tests dataclass-based state with optional field

All tests verify:

  1. Tool receives None when NotRequired field is absent
  2. Tool receives the actual value when NotRequired field is present
  3. No KeyError is raised in either case

Code Quality

  • ✅ Black formatting applied
  • ✅ Ruff linting passed
  • ✅ Follows existing code patterns
  • ✅ Comprehensive test coverage

Fixes langchain-ai/langchain#35585

Changed files

  • libs/langgraph/langgraph/pregel/main.py (modified, +34/-4)
  • libs/prebuilt/langgraph/prebuilt/tool_node.py (modified, +10/-10)
  • libs/prebuilt/tests/test_tool_node.py (modified, +135/-6)

PR #36192: fix: handle NotRequired InjectedState fields without KeyError

Description (problem / solution / changelog)

Summary

Fixes #35585.

InjectedState("field") on a NotRequired state field raises an unhandled KeyError when the field is absent from the state dict, because langgraph's ToolNode._inject_tool_args does a direct state[state_field] lookup.

This PR fixes the issue on the langchain side by introducing a ToolNode subclass in langchain/tools/tool_node.py that overrides _inject_tool_args:

  • Absent field + tool param has a default → skip injection, let the default apply naturally. This is the correct behaviour for NotRequired fields.
  • Absent field + tool param has no default → re-raise a KeyError with a clear message directing the user to either add a default or ensure the field is always populated.
  • All other cases → delegate to the langgraph base implementation unchanged.

langchain.agents.factory.create_agent now uses this subclass instead of importing ToolNode directly from langgraph.

What changed

  • libs/langchain_v1/langchain/tools/tool_node.py — new ToolNode subclass with _inject_tool_args override and a _tool_param_has_default helper.
  • libs/langchain_v1/langchain/agents/factory.py — import ToolNode from langchain.tools.tool_node instead of langgraph.prebuilt.tool_node.
  • libs/langchain_v1/tests/unit_tests/agents/test_create_agent_tool_validation.py — three new regression tests.

Test plan

  • test_injected_state_not_required_field_absent_with_default — absent NotRequired field, tool default (None) is used, no error.
  • test_injected_state_not_required_field_present — present NotRequired field is injected correctly.
  • test_injected_state_required_field_absent_raises — absent required field (no default) still raises KeyError.
  • All 726 existing agent unit tests pass.

🤖 Generated with Claude Code

Changed files

  • libs/langchain_v1/langchain/agents/factory.py (modified, +2/-1)
  • libs/langchain_v1/langchain/tools/tool_node.py (modified, +146/-4)
  • libs/langchain_v1/tests/unit_tests/agents/test_create_agent_tool_validation.py (modified, +135/-1)

PR #7392: fix(prebuilt): handle injected NotRequired keys

Description (problem / solution / changelog)

Resolves https://github.com/langchain-ai/langchain/issues/35585

This would previously raise KeyError:

from typing import Annotated

from langchain_core.tools import tool
from langchain.agents import create_agent
from typing_extensions import NotRequired
from langgraph.prebuilt import InjectedState
from langchain.agents import AgentState


class CustomAgentState(AgentState):
    city: NotRequired[str]


@tool
def get_weather(city: Annotated[str | None, InjectedState("city")] = None) -> str:
    """Get weather for a given city."""
    if city is None:
        city = "Boston"
    return f"It's always sunny in {city}!"


agent = create_agent(
    model="claude-sonnet-4-6",
    tools=[get_weather],
    system_prompt="You are a helpful assistant",
    state_schema=CustomAgentState,
)

input_message = {
    "role": "user",
    "content": "What's the weather?",
}

result = agent.invoke({"messages": [input_message]})
for m in result["messages"]:
    m.pretty_print()

Changed files

  • libs/prebuilt/langgraph/prebuilt/tool_node.py (modified, +19/-7)
  • libs/prebuilt/tests/test_injected_state_not_required.py (added, +284/-0)

Code Example

from typing import Annotated

from langchain_core.tools import tool
from langchain.agents import create_agent
from typing_extensions import NotRequired
from langgraph.prebuilt import InjectedState
from langchain.agents import AgentState


class CustomAgentState(AgentState):
    city: NotRequired[str]


@tool
def get_weather(city: Annotated[str, InjectedState("city")]) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"


def build_graph():
    """Build and compile the agent graph."""
    return create_agent(
        model="claude-sonnet-4-6",
        tools=[get_weather],
        system_prompt="You are a helpful assistant",
        state_schema=CustomAgentState,
    )

---

File ".../langgraph/prebuilt/tool_node.py", line 1358, in _inject_tool_args
    state[state_field] if state_field else state
    ~~~~~^^^^^^^^^^^^^
KeyError: 'city'

---

System Information
------------------
> OS:  Darwin
> OS Version:  Darwin Kernel Version 23.5.0: Wed May  1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000
> Python Version:  3.13.2 (main, Feb  4 2025, 14:51:09) [Clang 16.0.0 (clang-1600.0.26.6)]

Package Information
-------------------
> langchain_core: 1.2.17
> langchain: 1.2.10
> langsmith: 0.7.13
> langchain_anthropic: 1.3.4
> langchain_openai: 1.1.10
> langgraph_sdk: 0.3.9
RAW_BUFFERClick to expand / collapse

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

No response

Reproduction Steps / Example Code (Python)

from typing import Annotated

from langchain_core.tools import tool
from langchain.agents import create_agent
from typing_extensions import NotRequired
from langgraph.prebuilt import InjectedState
from langchain.agents import AgentState


class CustomAgentState(AgentState):
    city: NotRequired[str]


@tool
def get_weather(city: Annotated[str, InjectedState("city")]) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"


def build_graph():
    """Build and compile the agent graph."""
    return create_agent(
        model="claude-sonnet-4-6",
        tools=[get_weather],
        system_prompt="You are a helpful assistant",
        state_schema=CustomAgentState,
    )

Error Message and Stack Trace (if applicable)

File ".../langgraph/prebuilt/tool_node.py", line 1358, in _inject_tool_args
    state[state_field] if state_field else state
    ~~~~~^^^^^^^^^^^^^
KeyError: 'city'

Description

Description

When using InjectedState(<field>) on a tool parameter, and the referenced field is declared as NotRequired in the custom state schema, the ToolNode crashes with an unhandled KeyError if that field was never populated in the state.

We noticed this behaviour after upgrading to langchain >= 1.0.0. The same behaviour could not be reproduced with earlier versions.

System Info

System Information
------------------
> OS:  Darwin
> OS Version:  Darwin Kernel Version 23.5.0: Wed May  1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000
> Python Version:  3.13.2 (main, Feb  4 2025, 14:51:09) [Clang 16.0.0 (clang-1600.0.26.6)]

Package Information
-------------------
> langchain_core: 1.2.17
> langchain: 1.2.10
> langsmith: 0.7.13
> langchain_anthropic: 1.3.4
> langchain_openai: 1.1.10
> langgraph_sdk: 0.3.9

extent analysis

Fix Plan

1. Update langchain to the latest version

Ensure you have the latest version of langchain installed. You can do this by running:

pip install --upgrade langchain

2. Update langgraph to the latest version

Similarly, update langgraph to the latest version:

pip install --upgrade langgraph

3. Modify the CustomAgentState class

In the CustomAgentState class, modify the city field to be a required field instead of NotRequired:

class CustomAgentState(AgentState):
    city: str

4. Update the build_graph function

Update the build_graph function to pass the city field as a required field:

def build_graph():
    """Build and compile the agent graph."""
    return create_agent(
        model="claude-sonnet-4-6",
        tools=[get_weather],
        system_prompt="You are a helpful assistant",
        state_schema=CustomAgentState,
        state={"city": "New York"},  # Pass the city field as a required field
    )

Verification

To verify that the fix worked, run the build_graph function and check that it does not crash with a KeyError. You can also add some print statements to verify that the city field is being populated correctly.

def build_graph():
    """Build and compile the agent graph."""
    state = create_agent(
        model="claude-sonnet-4-6",
        tools=[get_weather],
        system_prompt="You are a helpful assistant",
        state_schema=CustomAgentState,
        state={"city": "New York"},  # Pass the city field as a required field
    )
    print(state["city"])  # Verify that

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

langchain - ✅(Solved) Fix InjectedState with a NotRequired state field raises KeyError when the field is absent from state [10 pull requests, 7 comments, 5 participants]