deepset-ai/haystack · error · ValueError

State: Key '{key}' not found in schema. Schema: {self.schema

Error message

State: Key '{key}' not found in schema. Schema: {self.schema}

What it means

State.set raises this ValueError when the key being written is not present in the State's schema. The schema is closed: only keys declared at construction can be set, which keeps merges deterministic.

Source

Thrown at haystack/components/agents/state/state.py:169

        """
        return deepcopy(self._data.get(key, default))

    def set(self, key: str, value: Any, handler_override: Callable[[Any, Any], Any] | None = None) -> None:
        """
        Set or merge a value in the state according to schema rules.

        Value is merged or overwritten according to these rules:
          - if handler_override is given, use that
          - else use the handler defined in the schema for 'key'

        :param key: Key to store the value under
        :param value: Value to store or merge
        :param handler_override: Optional function to override the default merge behavior
        """
        # If key not in schema, we throw an error
        definition = self.schema.get(key, None)
        if definition is None:
            raise ValueError(f"State: Key '{key}' not found in schema. Schema: {self.schema}")

        # Get current value from state and apply handler
        current_value = self._data.get(key, None)
        handler = handler_override or definition["handler"]
        self._data[key] = handler(current_value, value)

    @property
    def data(self) -> dict[str, Any]:
        """
        All current data of the state.
        """
        return self._data

    def has(self, key: str) -> bool:
        """
        Check if a key exists in the state.

        :param key: Key to check for existence

View on GitHub (pinned to e318778c9b)

Solutions

  1. Add the missing key to the state schema, e.g. {"foo": {"type": list}}
  2. Check tool output {"state_key": ...} mappings against the schema keys
  3. If the key shouldn't persist, return it only in the tool's string output instead of merging into state

Example fix

// before
agent = Agent(..., state_schema={"messages": {"type": list[ChatMessage]}})
# tool writes state_key="results"
// after
agent = Agent(..., state_schema={"messages": {"type": list[ChatMessage]}, "results": {"type": list}})
Defensive patterns

Strategy: validation

Validate before calling

def keys_in_schema(keys, schema):
    missing = [k for k in keys if k not in schema]
    if missing:
        raise KeyError(f"Keys not in schema: {missing}")

Type guard

def key_is_declared(key, schema) -> bool:
    return key in schema

Try / catch

try:
    state.set(key, value)
except ValueError as e:
    if "not found in schema" in str(e):
        state = State({**state.schema, key: {"type": type(value), "handler": None}}, state._data)
        state.set(key, value)
    else:
        raise

Prevention

When it happens

Trigger: Calling state.set("foo", value) where 'foo' was not declared in the schema passed to State/Agent; a tool output mapping writing an undeclared key; state_schema omitting a key that tools emit.

Common situations: Adding a new tool whose output mapping targets a state key not added to the Agent's state_schema, or renaming a schema key without updating tool configs.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/166411688696d83d. Report an issue: GitHub.