langchain-ai/deepagents · error · RuntimeError

StateBackend must be used inside a LangGraph graph…

Error message

StateBackend must be used inside a LangGraph graph execution (e.g. via create_deep_agent). It cannot read or write state outside of a graph context. To pre-populate files, pass them on invoke: agent.invoke({"messages": [...], "files": {...}})

What it means

`StateBackend` stores agent files in the LangGraph graph state, so it can only operate while a graph node is executing with a proper `RunnableConfig` in context. `_get_config` raises this `RuntimeError` when it cannot find a config (no graph execution context), meaning `_read_files` or `_send_files_update` was called outside a graph run. The message explains the remedy: pre-populate files on `invoke`, not by calling the backend directly.

Solutions

  1. Only use StateBackend inside graph execution — build the agent with `create_deep_agent` and call `agent.invoke({'messages': [...], 'files': {...}})` to pre-populate files
  2. In tests, use the project's fake config fixtures that inject CONFIG_KEY_READ/CONFIG_KEY_SEND (see error 616) or use a standalone backend (FilesystemBackend/StoreBackend) outside graphs
  3. If you need direct file access, switch to a backend that doesn't depend on graph state
  4. Ensure async/background work runs within the graph node's context, not after it returns

Example fix

// before
backend = StateBackend()
backend.write('/a.txt', 'hello')  # RuntimeError

// after
agent = create_deep_agent(backend=StateBackend(), tools=[...])
agent.invoke({'messages': [{'role': 'user', 'content': 'hi'}], 'files': {'/a.txt': 'hello'}})
Defensive patterns

Strategy: try-catch

Validate before calling

def state_backend_usable(config) -> bool:
    return config is not None and CONFIG_KEY_READ in config.get('configurable', {}) and CONFIG_KEY_SEND in config.get('configurable', {})

Try / catch

try:
    backend.write('/a.txt', 'x')
except RuntimeError as e:
    if 'graph execution' in str(e):
        agent.invoke({'messages': [...], 'files': {'/a.txt': 'x'}})  # seed via invoke instead
    else:
        raise

Prevention

When it happens

Trigger: Instantiating `StateBackend` and calling `read`/`write`/`delete`/`ls` (which reach `_get_config` via `_read_files`/`_send_files_update`) directly in application code, outside `create_deep_agent(...).invoke(...)`; calling it from a plain script, test, or thread without a LangGraph runtime context.

Common situations: Trying to inspect or seed files before invoking the agent; unit-testing the backend without a fake graph config; background threads/callbacks that outlive the graph node and lose the config context.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/aaa75d342012cf29. Report an issue: GitHub.

Appendix: source

Thrown at libs/deepagents/deepagents/backends/state.py:68

    def __init__(self) -> None:
        """Initialize StateBackend."""

    # ------------------------------------------------------------------
    # Internal helpers for reading / writing state via config keys
    # ------------------------------------------------------------------

    def _get_config(self) -> RunnableConfig:
        """Return the current LangGraph config, with a clear error if missing."""
        try:
            config = get_config()
        except RuntimeError:
            msg = (
                "StateBackend must be used inside a LangGraph graph execution "
                "(e.g. via create_deep_agent). It cannot read or write state "
                "outside of a graph context. To pre-populate files, pass them "
                'on invoke: agent.invoke({"messages": [...], "files": {...}})'
            )
            raise RuntimeError(msg) from None
        configurable = config.get("configurable", {})
        if CONFIG_KEY_READ not in configurable:
            msg = (
                "StateBackend requires CONFIG_KEY_READ / CONFIG_KEY_SEND in "
                "the LangGraph config. Make sure the backend is used inside "
                "a graph node or tool, not called directly. To pre-populate "
                "files, pass them on invoke: "
                'agent.invoke({"messages": [...], "files": {...}})'
            )
            raise RuntimeError(msg)
        return config

    def _read_files(self) -> dict[str, Any]:
        """Read the current `files` channel via Pregel internals.

        Uses `CONFIG_KEY_READ` to read state directly — this lets us
        initialize StateBackend once and fetch state on demand from any
        graph context (tools, middleware nodes, etc.).

View on GitHub (pinned to a1af029e6e)