# https://github.com/langchain-ai/langgraph Project Manual

Generated at: 2026-06-03 05:55:45 UTC

## Table of Contents

- [Core Graph Construction and Runtime](#page-1)
- [Prebuilt Agents, Tools, and Common Errors](#page-2)
- [Checkpointing, Serialization, and Stores](#page-3)
- [CLI, Python SDK, and Deployment Workflows](#page-4)

<a id='page-1'></a>

## Core Graph Construction and Runtime

### Related Pages

Related topics: [Prebuilt Agents, Tools, and Common Errors](#page-2), [Checkpointing, Serialization, and Stores](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [libs/langgraph/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/README.md)
- [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md)
- [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)
- [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)
- [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py)
- [libs/cli/python-monorepo-example/apps/agent/src/agent/state.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/python-monorepo-example/apps/agent/src/agent/state.py)
- [libs/cli/js-examples/src/agent/graph.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/graph.ts)
- [libs/cli/js-examples/src/agent/state.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)
- [libs/cli/js-examples/package.json](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/package.json)
- [libs/cli/js-examples/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/README.md)
- [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
- [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)
- [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md)
</details>

# Core Graph Construction and Runtime

## 1. Purpose and Scope

LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents and workflows. The "core graph construction and runtime" layer is the part of the framework a developer interacts with directly: defining state, declaring nodes, wiring edges, compiling the graph, and invoking it at run time. The README positions LangGraph around three pillars — durable execution, human-in-the-loop, and comprehensive memory — all of which depend on this construction and runtime layer [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md).

The runtime is inspired by Google's Pregel and Apache Beam (BSP-style supersteps), while the public surface draws from NetworkX. The construction layer (`StateGraph`, `Annotation`, reducers) hides the BSP engine behind an ergonomic, typed API [libs/langgraph/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/README.md).

## 2. High-Level Architecture

```mermaid
graph TD
    A[State Definition<br/>TypedDict / Annotation] --> B[StateGraph Builder]
    B --> C[addNode: functions / runnables]
    C --> D[addEdge / addConditionalEdges]
    D --> E[compile]
    E --> F[Pregel Runtime]
    F --> G[Channels & Reducers]
    F --> H[Checkpoint Saver<br/>optional]
    F --> I[invoke / stream / batch]
    H --> J[(Thread Store<br/>SQLite / Postgres / in-memory)]
```

The graph is a *description* until `.compile()` is called; only then does the Pregel runtime materialize channels, wire nodes into supersteps, and attach the (optional) checkpointer.

## 3. State Definition

State is the typed record that flows between nodes. There are two equivalent styles: Python's `TypedDict` plus `Annotated` reducers, and the JS `Annotation.Root` helper.

### 3.1 Python — TypedDict + `add_messages`

The canonical pattern accumulates chat history via a reducer so concurrent branches can append without losing messages. The reference state lives in the CLI's Python monorepo example [libs/cli/python-monorepo-example/apps/agent/src/agent/state.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/python-monorepo-example/apps/agent/src/agent/state.py):

```python
from collections.abc import Sequence
from typing import Annotated, TypedDict

from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages


class State(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
```

The `Annotated[..., add_messages]` form tells the runtime to use `add_messages` (defined in `langgraph.graph.message`) to merge partial updates into the existing `messages` channel. The same shape is used in the simpler "uv-examples" template [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py).

### 3.2 TypeScript — `Annotation.Root`

The JS example mirrors the pattern using `Annotation.Root` and `messagesStateReducer` [libs/cli/js-examples/src/agent/state.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts):

```ts
import { Annotation, messagesStateReducer } from "@langchain/langgraph";

export const StateAnnotation = Annotation.Root({
  messages: Annotation<BaseMessage[], BaseMessageLike[]>({
    reducer: messagesStateReducer,
    default: () => [],
  }),
});
```

In both languages a *reducer* is the function that decides how an incoming update merges with the current value; the type checker can validate the inferred types as nodes and edges are added.

## 4. Building the Graph

### 4.1 Adding Nodes

A node is any callable that takes the current state (and optionally `RunnableConfig`) and returns a *subset* of the state fields it wants to update. From the JS starter [libs/cli/js-examples/src/agent/graph.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/graph.ts):

```ts
const callModel = async (
  state: typeof StateAnnotation.State,
  _config: RunnableConfig,
): Promise<typeof StateAnnotation.Update> => {
  // returns a partial update, e.g. { messages: [aiMessage] }
};
```

In Python, the same function returns a `dict` whose keys must exist on `State` [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py):

```python
def call_model(state: State) -> dict:
    message = AIMessage(content="Hello from simple uv agent!")
    return {"messages": [message]}
```

### 4.2 Edges

There are two edge kinds in both languages:

| Edge kind | Python | TypeScript | Semantics |
|---|---|---|---|
| Static | `add_edge("a", "b")` | `.addEdge("a", "b")` | Always transitions to `b` after `a` finishes |
| Conditional | `add_conditional_edges("a", router_fn, path_map)` | `.addConditionalEdges("a", routerFn, pathMap)` | Router returns a node name (or `END`) |

`__start__` and `__end__` are virtual nodes: `__start__` represents graph entry, `__end__` represents a terminal state. The example routers return either `"callModel"` to loop or `END` to finish [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py).

### 4.3 End-to-End Construction (Python)

```python
from langgraph.graph import END, START, StateGraph

workflow = StateGraph(State)
workflow.add_node("call_model", call_model)
workflow.add_edge(START, "call_model")
workflow.add_conditional_edges(
    "call_model",
    should_continue,
    {END: END, "call_model": "call_model"},
)
graph = workflow.compile()
```

Source: [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py).

### 4.4 End-to-End Construction (TypeScript)

```ts
const builder = new StateGraph(StateAnnotation)
  .addNode("callModel", callModel)
  .addEdge("__start__", "callModel")
  .addConditionalEdges("callModel", route);

export const graph = builder.compile();
graph.name = "New Agent";
```

Source: [libs/cli/js-examples/src/agent/graph.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/graph.ts).

## 5. State, Channels, and Reducers

A graph's `State` schema is materialized at compile time into a set of *channels*. Each channel owns the versioned storage for one state field and a *reducer* that applies a node's partial return value.

| Channel concept | Role |
|---|---|
| Channel value | The current per-field value |
| Reducer | Function that merges an update with the existing value |
| `add_messages` | Default reducer for `Sequence[BaseMessage]`; handles dedup by ID and append semantics |
| Last-value | Default reducer when no reducer is specified: each update overwrites |

The default `JsonPlusSerializer` in `langgraph-checkpoint` ships the values to durable storage. Note the security guidance: by default the serializer can deserialize arbitrary Python types found in checkpoint data, so applications should set `LANGGRAPH_STRICT_MSGPACK=true` or pass an explicit `allowed_msgpack_modules` list [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md).

## 6. Compilation

`.compile()` is the boundary between *description* and *runnable*. Internally it:

1. Validates the graph topology (no unreachable nodes, no cycles without conditional escape, etc.).
2. Materializes channels from the `State` schema and reducer annotations.
3. Wires nodes into the Pregel execution plan.
4. Optionally attaches a checkpointer and an interrupt / human-in-the-loop configuration.
5. Returns a `Pregel` instance exposing `invoke`, `stream`, `async for` iteration, and `batch` entry points.

The compiled graph is a `Pregel` runtime object; the public interface is the same regardless of whether persistence is enabled.

## 7. Runtime Execution (Pregel Model)

The runtime runs the graph in *supersteps*. Within a superstep:

1. The runtime reads channel values for the nodes scheduled at the start of the step.
2. Each node runs (optionally in parallel for fan-out via `Send`).
3. Each node's returned partial state is applied through the channel's reducer.
4. Conditional edges pick next nodes; static edges schedule their target.
5. If a checkpointer is configured, a checkpoint is written for the post-superstep state.
6. The next superstep begins with the freshly updated state.

```mermaid
graph TD
    S0[Superstep N begin] --> R[Read scheduled nodes & channels]
    R --> N[Run nodes in parallel]
    N --> A[Apply partial updates via reducers]
    A --> E[Evaluate conditional edges]
    E --> CK{New checkpoint?}
    CK -- yes --> CP[Persist checkpoint + pending writes]
    CK -- no --> NS
    CP --> NS[Compute next superstep nodes]
    NS --> S0
```

If a node fails mid-superstep, the successfully completed writes are kept as *pending writes* so that on resume the failing node is re-executed but the successful siblings are not [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md).

## 8. Invocation Patterns

The compiled `Pregel` object is a LangChain `Runnable` and supports the standard surface:

| Method | Purpose |
|---|---|
| `invoke(input, config)` | Run to completion, return final state |
| `stream(input, config)` | Yield intermediate state per superstep (or per node with mode) |
| `astream_events` | Token-level / event-level streaming for UI |
| `batch(inputs)` | Run multiple inputs in parallel |

The Python SDK exposes the same lifecycle over HTTP against a running LangGraph API server [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md):

```python
from langgraph_sdk import get_client

client = get_client()
thread = await client.threads.create()
async for chunk in client.runs.stream(
    thread["thread_id"], agent["assistant_id"], input=input
):
    print(chunk)
```

When you need a local server for development, `langgraph dev` (in-process, hot reload) or `langgraph up` (Dockerized) start the API server that the SDK connects to [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md).

## 9. Configuration: `config.configurable`

Runtime configuration is passed alongside `input` and is the canonical mechanism for selecting a `thread_id`, `checkpoint_id`, and (post-v1) a typed `context`. The checkpoint README shows the accepted shape [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md):

```python
{"configurable": {"thread_id": "1"}}
{"configurable": {"thread_id": "1", "checkpoint_id": "0c62ca34-ac19-445d-bbb0-5b4984975b2a"}}
```

`thread_id` is always required when a checkpointer is attached; `checkpoint_id` is optional and is used to resume from a specific point. The community is actively iterating on a v1 `config.configurable -> context` API to make passing immutable per-run context more discoverable; this is one of the most-upvoted feedback threads and is worth following if you design new graphs today [issue #5023](https://github.com/langchain-ai/langgraph/issues/5023). The v1 roadmap discussion also covers planned changes to the low-level `StateGraph` API [issue #4973](https://github.com/langchain-ai/langgraph/issues/4973).

## 10. Persistence and Checkpointing

Checkpointers plug into the runtime at compile time. The `BaseCheckpointSaver` interface defines three operations: `.put`, `.put_writes`, and `.get_tuple` [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md). Concrete implementations live in separate packages:

| Saver | Package | Notes |
|---|---|---|
| In-memory | `langgraph.checkpoint.memory` | Default in dev, no durability |
| SQLite (sync & async) | `langgraph-checkpoint-sqlite` | Local single-process persistence; see `AsyncSqliteSaver.from_conn_string` [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md) |
| Postgres | `langgraph-checkpoint-postgres` | Production / multi-replica; known to have SSL negotiation issues in some versions that are tracked in the community [issue #3716](https://github.com/langchain-ai/langgraph/issues/3716) |

Pending writes are how the runtime preserves work when a superstep partially fails — they are stored against the failing checkpoint and replayed deterministically on resume [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md).

## 11. Prebuilt Components on Top of the Core

The prebuilt library layers high-level abstractions on the same runtime [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md):

- `create_react_agent(model, tools)` — Builds a tool-calling ReAct agent using the same `StateGraph` API under the hood.
- `ToolNode` — A pre-built node that executes a list of `BaseTool` instances and returns `ToolMessage` results.

When using `create_react_agent` with a tool that touches `BaseStore`, be aware of an open issue around `Send` not being msgpack-serializable inside the tool branch; this surfaces as `TypeError: Type is not msgpack serializable: Send` when paired with a non-strict serializer [issue #5891](https://github.com/langchain-ai/langgraph/issues/5891). Setting `LANGGRAPH_STRICT_MSGPACK=true` typically works around it by routing through a stricter code path.

## 12. Common Failure Modes

| Symptom | Likely cause | Where to look |
|---|---|---|
| `InvalidUpdateError: Must write to at least one of [...]` | A node returned an empty dict, or none of its keys are present in the state schema | Verify the return value of each node; check the schema in `State` [issue #740](https://github.com/langchain-ai/langgraph/issues/740) |
| `TypeError: Type is not msgpack serializable: Send` | Non-serializable object reached the checkpoint layer | Restrict via `LANGGRAPH_STRICT_MSGPACK=true` or `allowed_msgpack_modules` [issue #5891](https://github.com/langchain-ai/langgraph/issues/5891) |
| `psycopg.OperationalError: SSL error: bad length` (postgres) | SSL / libpq mismatch in some versions of `langgraph-checkpoint-postgres` | Track against pinned versions and the open thread [issue #3716](https://github.com/langchain-ai/langgraph/issues/3716) |
| Channel value lost after parallel branches | No reducer on the channel, so last-writer-wins | Add a reducer in `Annotated[..., reducer]` or `Annotation.Root` |

## 13. Putting It Together

The smallest complete Python graph from the templates looks like this [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py):

```python
from collections.abc import Sequence
from typing import Annotated, TypedDict

from langchain_core.messages import AIMessage, BaseMessage
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages


class State(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]


def call_model(state: State) -> dict:
    return {"messages": [AIMessage(content="Hello from simple uv agent!")]}


def should_continue(state: State):
    if len(state["messages"]) > 0:
        return END
    return "call_model"


workflow = StateGraph(State)
workflow.add_node("call_model", call_model)
workflow.add_edge(START, "call_model")
workflow.add_conditional_edges("call_model", should_continue)
graph = workflow.compile()
```

The TypeScript equivalent in the JS starter template produces the same runtime behavior, just with `Annotation.Root` and string node names [libs/cli/js-examples/src/agent/graph.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/graph.ts).

## See Also

- [LangGraph documentation portal](https://docs.langchain.com/oss/python/langgraph/overview)
- [LangGraph API reference](https://reference.langchain.com/python/langgraph/)
- [Checkpointing and serialization](https://docs.langchain.com/oss/python/langgraph/persistence)
- [Durable execution](https://docs.langchain.com/oss/python/langgraph/durable-execution)
- [Human-in-the-loop / interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts)
- [LangGraph CLI](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
- [LangGraph Python SDK](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)
- [LangGraph.js (JS / TS port)](https://github.com/langchain-ai/langgraphjs)
- Related community threads: [v1 roadmap #4973](https://github.com/langchain-ai/langgraph/issues/4973), [context API #5023](https://github.com/langchain-ai/langgraph/issues/5023), [InvalidUpdateError #740](https://github.com/langchain-ai/langgraph/issues/740), [msgpack + Send #5891](https://github.com/langchain-ai/langgraph/issues/5891), [postgres SSL #3716](https://github.com/langchain-ai/langgraph/issues/3716)

---

<a id='page-2'></a>

## Prebuilt Agents, Tools, and Common Errors

### Related Pages

Related topics: [Core Graph Construction and Runtime](#page-1), [Checkpointing, Serialization, and Stores](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)
- [libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py)
- [libs/prebuilt/langgraph/prebuilt/tool_node.py](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/langgraph/prebuilt/tool_node.py)
- [libs/prebuilt/langgraph/prebuilt/tool_validator.py](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/langgraph/prebuilt/tool_validator.py)
- [libs/prebuilt/langgraph/prebuilt/interrupt.py](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/langgraph/prebuilt/interrupt.py)
- [libs/langgraph/langgraph/errors.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/errors.py)
- [libs/langgraph/langgraph/pregel/_validate.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/pregel/_validate.py)
- [libs/langgraph/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/README.md)
- [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md)
- [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
- [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)
- [libs/cli/js-examples/src/agent/state.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)
- [libs/cli/js-examples/package.json](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/package.json)
- [libs/cli/js-examples/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/README.md)
</details>

# Prebuilt Agents, Tools, and Common Errors

LangGraph ships a "prebuilt" layer (`langgraph-prebuilt`) that bundles the most common agentic and tool-calling patterns into a small set of ready-to-use components. These components are intended to be imported from `langgraph.prebuilt` (the package is bundled with `langgraph` and should not be installed directly) [Source: [libs/prebuilt/README.md:1-7](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

This page documents the public surface of that prebuilt layer — the `create_react_agent` factory, `ToolNode`, `ValidationNode`, the Agent Inbox `HumanInterrupt` schema — and walks through the most common runtime and serialization errors that users encounter when wiring these components together, as evidenced by the GitHub issues with the highest engagement in the community.

## Overview

The prebuilt layer sits *above* the low-level `StateGraph` API. Instead of declaring nodes, reducers, and edges by hand, you can import higher-level building blocks:

| Component | Module | Purpose |
|-----------|--------|---------|
| `create_react_agent` | `langgraph.prebuilt.chat_agent_executor` | Assemble a tool-calling ReAct agent graph from a model + tools |
| `ToolNode` | `langgraph.prebuilt.tool_node` | Execute tool calls emitted by a chat model |
| `ValidationNode` | `langgraph.prebuilt.tool_validator` | Validate tool arguments against a Pydantic schema before execution |
| `HumanInterrupt` / `HumanResponse` | `langgraph.prebuilt.interrupt` | Schemas for the Agent Inbox human-in-the-loop protocol |

Source: [libs/prebuilt/README.md:1-12](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

```mermaid
graph TD
    A[User Input] --> B[LLM Node]
    B -->|tool_calls present| C{ToolNode / ValidationNode}
    B -->|no tool calls| D[End]
    C -->|valid| E[Execute Tool]
    C -->|invalid| B
    E --> B
    B -->|interrupt| F[Agent Inbox HumanInterrupt]
    F -->|HumanResponse| B
```

The prebuilt layer still rides on the underlying Pregel/StateGraph execution engine, which is what surfaces the structured error classes covered in the *Common Errors* section below.

## Prebuilt Agents

### `create_react_agent`

`create_react_agent` is the most common entry point. It returns a compiled `StateGraph` that you can `.invoke()`, `.stream()`, or `.batch()` the same way as a graph you built by hand [Source: [libs/prebuilt/README.md:11-30](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

```python
from langchain_anthropic import ChatAnthropic
from langgraph.prebuilt import create_react_agent

def search(query: str):
    """Call to surf the web."""
    if "sf" in query.lower() or "san francisco" in query.lower():
        return "It's 60 degrees and foggy."
    return "It's 90 degrees and sunny."

tools = [search]
model = ChatAnthropic(model="claude-3-7-sonnet-latest")

app = create_react_agent(model, tools)
app.invoke({"messages": [{"role": "user", "content": "what is the weather in sf"}]})
```

Source: [libs/prebuilt/README.md:15-30](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

#### What you get

`create_react_agent` produces a `StateGraph` whose state includes a `messages` channel. The reducer used for that channel is the standard append-with-id-merge behavior: messages are appended, and any incoming message sharing an `id` with an existing one replaces it. This guarantees an "append-only" conversational history by default [Source: [libs/cli/js-examples/src/agent/state.ts:34-58](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)].

#### State shape

| Field | Type | Reducer | Default | Notes |
|-------|------|---------|---------|-------|
| `messages` | `BaseMessage[]` (in) / `BaseMessageLike[]` (in) | `messagesStateReducer` | `[]` | Coerces message-like dicts to LangChain `BaseMessage` instances, assigns IDs, replaces duplicates |
| *(custom)* | any | *optional* | *optional* | Add additional fields by extending the schema; non-reducer fields are overwritten by node return values |

Source: [libs/cli/js-examples/src/agent/state.ts:34-62](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)

### When to reach past the prebuilt

The prebuilt agents are intentionally minimal. If you need plan/reflect loops, sub-agents, file-system tools, or task delegation, the README points you to **Deep Agents**, a higher-level package built on top of LangGraph [Source: [README.md:25-29](https://github.com/langchain-ai/langgraph/blob/main/README.md)].

## Prebuilt Tools

### `ToolNode`

`ToolNode` is a graph node that consumes the last `AIMessage` from the `messages` channel and runs every `tool_call` it finds, appending the resulting `ToolMessage` instances back into state [Source: [libs/prebuilt/README.md:32-50](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

```python
from langgraph.prebuilt import ToolNode
from langchain_core.messages import AIMessage

def search(query: str):
    """Call to surf the web."""
    if "sf" in query.lower() or "san francisco" in query.lower():
        return "It's 60 degrees and foggy."
    return "It's 90 degrees and sunny."

tool_node = ToolNode([search])
tool_calls = [{"name": "search", "args": {"query": "what is the weather in sf"}, "id": "1"}]
ai_message = AIMessage(content="", tool_calls=tool_calls)
tool_node.invoke({"messages": [ai_message]})
```

Source: [libs/prebuilt/README.md:43-50](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

### `ValidationNode`

`ValidationNode` wraps tool calls in a Pydantic model so that arguments are validated **before** the underlying tool runs. If validation fails, the model error is sent back to the LLM as a `ToolMessage`, allowing the model to self-correct [Source: [libs/prebuilt/README.md:52-77](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

```python
from pydantic import BaseModel, field_validator
from langgraph.prebuilt import ValidationNode
from langchain_core.messages import AIMessage

class SelectNumber(BaseModel):
    a: int

    @field_validator("a")
    def a_must_be_meaningful(cls, v):
        if v != 37:
            raise ValueError("Only 37 is allowed")
        return v

validation_node = ValidationNode([SelectNumber])
validation_node.invoke({
    "messages": [AIMessage("", tool_calls=[{"name": "SelectNumber", "args": {"a": 42}, "id": "1"}])]
})
```

Source: [libs/prebuilt/README.md:64-77](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

### ToolNode vs. ValidationNode

| Concern | `ToolNode` | `ValidationNode` |
|---------|-----------|------------------|
| Runs the tool | ✅ | ❌ (delegates to `ToolNode` internally for valid calls) |
| Validates args with Pydantic | ❌ | ✅ |
| Returns validation errors to the LLM | n/a | ✅ (as `ToolMessage`) |
| Typical use | Trusted, well-typed tools | Untrusted user input or open-ended tool sets |

Source: [libs/prebuilt/README.md:32-77](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

## Agent Inbox and Human-in-the-Loop

The prebuilt layer ships the schemas used by the [Agent Inbox](https://github.com/langchain-ai/agent-inbox) human-in-the-loop UI. The flow is: a tool call is intercepted, an interrupt is raised, a human approves/ignores/edits the action, and execution resumes with a `HumanResponse` [Source: [libs/prebuilt/README.md:79-102](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

```python
from langgraph.types import interrupt
from langgraph.prebuilt.interrupt import HumanInterrupt, HumanResponse

def my_graph_function():
    tool_call = state["messages"][-1].tool_calls[0]
    request: HumanInterrupt = {
        "action_request": {
            "action": tool_call['name'],
            "args": tool_call['args']
        },
        "config": {
            "allow_ignore": True,
            # ...other Agent Inbox config...
        },
    }
    response: HumanResponse = interrupt([request])[0]
    # ...handle response...
```

Source: [libs/prebuilt/README.md:88-102](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

```mermaid
graph TD
    A[LLM proposes tool_call] --> B[Graph node calls interrupt&#40;[HumanInterrupt]&#41;]
    B --> C[LangGraph persists state and pauses run]
    C --> D[Agent Inbox UI]
    D -->|approve / edit / ignore| E[HumanResponse written to thread state]
    E --> F[Graph resumes from interrupt point]
    F --> G[ToolNode executes or skips the tool]
```

Human-in-the-loop is one of the headline features of LangGraph and is documented at length in the public docs. The `interrupt` primitive plus the prebuilt `HumanInterrupt` / `HumanResponse` schemas are the canonical way to plug into it [Source: [README.md:39-43](https://github.com/langchain-ai/langgraph/blob/main/README.md)].

## Common Errors

The prebuilt layer is small, but the runtime underneath it (Pregel + checkpointers) is where most user-facing errors come from. The following are the failure modes that surface most often in the issue tracker.

### `InvalidUpdateError`: "Must write to at least one of [...]"

**Symptom**

```
langgraph.errors.InvalidUpdateError: Must write to at least one of ['input', 'plan', 'past_steps', 'response']
```

**Cause**

A node returned a state delta that did not include any of the channels declared in the graph's state schema. This is almost always caused by:

1. A node returns `None` or an empty dict while the state's `Annotated` reducers expect *some* channel to be updated.
2. A conditional edge returns a route name that no longer exists after a refactor of the state schema.
3. A subgraph returns a partial state that does not overlap with the channels the parent graph is waiting for.

**Fix sketch**

- Confirm every node's return value contains at least one key in the union of channels listed in the error.
- If the channel is annotated with a reducer (e.g. `Annotated[list[BaseMessage], add_messages]`), the reducer handles `None` only when the default factory is in place; explicit `None` returns still fail validation in some configurations.
- For subgraphs, the parent graph's channel names and the subgraph's output keys must overlap, otherwise the parent raises this error when it tries to merge the result.

Source: GitHub issue #740 (35 comments) — community thread on `InvalidUpdateError`; mechanism documented in [libs/langgraph/langgraph/errors.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/errors.py) and the Pregel validator at [libs/langgraph/langgraph/pregel/_validate.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/pregel/_validate.py).

### `TypeError: Type is not msgpack serializable: Send`

**Symptom**

```
TypeError: Type is not msgpack serializable: Send
```

raised from inside `create_react_agent` when a tool implementation closes over a `BaseStore` (or another non-msgpack-serializable object) and tries to return a `Send` packet through a Pregel channel.

**Cause**

Pregel persists every channel update — including `Send` packets used for map-reduce style fan-out — using the configured checkpointer's serializer. By default that is msgpack. `langgraph.types.Send` and any captured objects must be msgpack-serializable, but tools that close over `BaseStore`, locks, database connections, or asyncio primitives are not.

**Fix sketch**

- Make the captured dependency serializable (e.g. store a `store_id` and re-resolve the `BaseStore` inside the tool via `get_store()` / runtime context).
- Avoid returning `Send` directly from inside a `create_react_agent` tool; emit a normal `ToolMessage` and let the agent loop decide.
- If you must use custom packets, supply a custom serializer to the checkpointer that knows how to encode `Send`.

Source: GitHub issue #5891 (7 comments) — `TypeError: Type is not msgpack serializable: Send` when using `create_react_agent` with a `BaseStore`-backed tool.

### `psycopg.OperationalError: SSL error: bad length` (Postgres checkpointer)

**Symptom**

```
psycopg.OperationalError: sending query and params failed: SSL error: bad length
```

emitted by `langgraph-checkpoint-postgres` across multiple versions.

**Cause**

This is a connection-level SSL failure between the Python runtime and Postgres, not a LangGraph bug per se. Common root causes reported in the thread:

- A proxy or load balancer between the app and Postgres is mangling SSL records.
- Mixing `sslmode=require` with a server that expects `sslmode=verify-full`.
- Reusing a connection across an event loop boundary with a non-async psycopg driver.

**Fix sketch**

- Pin the SSL mode to match what your Postgres host advertises (`sslmode=require` vs `verify-full`).
- Ensure you are using the async `AsyncPostgresSaver` from an async context and the sync `PostgresSaver` from sync code; do not interleave.
- Disable any intermediate proxies that re-encrypt SSL.

Source: GitHub issue #3716 (48 comments) — `langgraph-checkpoint-postgres` SSL error across multiple versions.

### `config.configurable` confusion and the proposed `context` API

**Symptom**

Users routinely try to pass per-run, immutable configuration (e.g. user IDs, feature flags) to nodes and runnables, and reach for `config["configurable"]` because that is the LangChain convention. Inside a graph node, however, `config["configurable"]` is merged with LangGraph's *own* `configurable` keys (thread ID, checkpoint NS, etc.), which leads to subtle bugs and "I can't find my key" errors.

**Status**

The maintainers have proposed a dedicated `context` API to make passing immutable per-run context to nodes explicit and type-safe. As of the v1.2.4 release this is still under design discussion, so users building on `langgraph` today should keep using `config["configurable"]` for ad-hoc values, but avoid namespacing their keys under LangGraph's reserved prefixes [Source: [libs/langgraph/langgraph/errors.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/errors.py); community discussion: GitHub issue #5023 (14 comments)].

Source: GitHub issue #5023 — "`config.configurable` -> `context` API" feedback thread (14 comments).

### Mapping error → component

| Error | Most likely layer | First place to look |
|-------|-------------------|---------------------|
| `InvalidUpdateError: Must write to at least one of [...]` | Pregel channel validation | State schema and node return values |
| `TypeError: Type is not msgpack serializable: Send` | Checkpointer serialization | Tools that close over `BaseStore` / non-serializable objects |
| `psycopg.OperationalError ... SSL error: bad length` | `langgraph-checkpoint-postgres` transport | Connection URL SSL mode and driver choice |
| `KeyError` on `config["configurable"][...]` | Graph runtime config | Namespacing vs. the proposed `context` API |

Source: aggregated from GitHub issues #740, #5891, #3716, #5023 and the source files cited above.

## Configuration and CLI Adjacencies

While the prebuilt layer itself takes Python objects directly, it is most often deployed via the LangGraph CLI and SDK. The CLI's `langgraph dev` (in-memory, hot-reload) and `langgraph up` (Docker) commands are the canonical local entry points [Source: [libs/cli/README.md:13-44](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)]:

| Command | Default port | Reload | Browser | Config |
|---------|--------------|--------|---------|--------|
| `langgraph dev` | `2024` | ✅ (unless `--no-reload`) | ✅ (unless `--no-browser`) | `langgraph.json` |
| `langgraph up` | `8123` (Docker) | `--watch` | n/a | `langgraph.json`, optional `-d` compose |
| `langgraph build` | n/a | n/a | n/a | `-t` tag |

Source: [libs/cli/README.md:13-56](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)

For deployed graphs, the `langgraph-sdk` Python client is the typed surface for assistants, threads, and runs; it defaults to `http://localhost:8123` when used with `langgraph-cli` [Source: [libs/sdk-py/README.md:7-31](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)].

## Usage Patterns

### Minimal tool-calling agent

```python
from langchain_anthropic import ChatAnthropic
from langgraph.prebuilt import create_react_agent

def get_weather(city: str) -> str:
    return "sunny" if "sf" in city.lower() else "unknown"

app = create_react_agent(
    ChatAnthropic(model="claude-3-7-sonnet-latest"),
    [get_weather],
)
app.invoke({"messages": [{"role": "user", "content": "weather in sf?"}]})
```

Source: [libs/prebuilt/README.md:15-30](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

### Validated tools

Use `ValidationNode` between the LLM node and the executing `ToolNode` when tool inputs come from untrusted text. Validation errors are returned to the model, which can retry with corrected arguments [Source: [libs/prebuilt/README.md:52-77](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

### Human approval via Agent Inbox

Combine `interrupt` with the `HumanInterrupt` / `HumanResponse` schemas to require a human sign-off on every tool call. The pattern is identical whether the agent is built with `create_react_agent` or with a hand-rolled `StateGraph` [Source: [libs/prebuilt/README.md:79-102](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)].

## Common Failure Modes (Cheat Sheet)

| Failure | Root cause | Mitigation |
|---------|-----------|------------|
| `InvalidUpdateError: Must write to at least one of [...]` | Node returned delta missing all expected channels | Make every node return at least one channel key; align subgraph outputs with parent channels |
| `TypeError: Type is not msgpack serializable: Send` | Tool closure captures non-serializable object (e.g. `BaseStore`) | Re-resolve the store via runtime context, or avoid `Send` inside the tool |
| `psycopg.OperationalError ... SSL error: bad length` | Mismatched `sslmode` / proxy re-encryption | Match `sslmode` to server; use the async/sync saver that matches your event loop |
| `KeyError` on `config["configurable"][...]` | Key collision with LangGraph-reserved namespacing | Namespace your keys (`config["configurable"]["my_app.user_id"]`); track the proposed `context` API |
| Agent "loops forever" on a tool error | Tool raises an unhandled exception | Catch exceptions inside the tool and return a string error; consider `ValidationNode` |
| Checkpoint corruption after upgrade | Serializer/version mismatch | Use a fresh thread ID or wipe the checkpointer when bumping `langgraph` major versions |

Sources: GitHub issues #740, #5891, #3716, #5023; [libs/langgraph/langgraph/errors.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/errors.py); [libs/langgraph/langgraph/pregel/_validate.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/pregel/_validate.py).

## See Also

- LangGraph overview and durable execution: [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md)
- Prebuilt reference (`create_react_agent`, `ToolNode`, `ValidationNode`): [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)
- Pregel channel validation: [libs/langgraph/langgraph/pregel/_validate.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/pregel/_validate.py)
- Error classes: [libs/langgraph/langgraph/errors.py](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/langgraph/errors.py)
- CLI commands for local dev and Docker: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
- Python SDK for deployed graphs: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)
- Community discussion on the proposed `context` API: GitHub issue #5023
- Community discussion on `InvalidUpdateError`: GitHub issue #740
- Community discussion on `TypeError: ... is not msgpack serializable: Send`: GitHub issue #5891
- Community discussion on `langgraph-checkpoint-postgres` SSL errors: GitHub issue #3716
- v1 roadmap and feedback: GitHub issue #4973

---

<a id='page-3'></a>

## Checkpointing, Serialization, and Stores

### Related Pages

Related topics: [Core Graph Construction and Runtime](#page-1), [CLI, Python SDK, and Deployment Workflows](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)
- [libs/checkpoint-conformance/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-conformance/README.md)
- [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md)
- [libs/checkpoint-postgres/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-postgres/README.md)
- [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)
- [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md)
- [libs/langgraph/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/langgraph/README.md)
- [libs/cli/js-examples/src/agent/state.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)
</details>

# Checkpointing, Serialization, and Stores

LangGraph's persistence layer rests on three interlocking concerns: **checkpointing** (capturing graph state at every superstep), **serialization** (turning that state into something a storage backend can write and read), and **stores** (long-term, cross-thread key/value memory that complements per-thread checkpoints). This page documents the contracts, the bundled implementations, and the operational pitfalls that the community most often hits.

## Overview

The high-level role of these three subsystems, drawn from the top-level repository README and the checkpoint library description:

- **Checkpointing** makes LangGraph *durable* and *resumable*. At every superstep, a checkpointer records a snapshot of channel values, channel versions, and pending writes so a run can be resumed, replayed, branched, or inspected for human-in-the-loop workflows. Source: [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md) — "Durable execution — Build agents that persist through failures and can run for extended periods, automatically resuming from exactly where they left off."
- **Serialization (serde)** is the protocol that turns Python objects (LangChain messages, datetimes, enums, custom pydantic models, etc.) into bytes the checkpointer can store, and reconstructs them on read. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — "`langgraph_checkpoint` also defines protocol for serialization/deserialization (serde)…"
- **Stores** are a separate persistence primitive (`BaseStore`) used by the prebuilt `create_react_agent` for long-term, cross-thread memory — distinct from a thread-scoped `checkpointer`. Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md) — "`langgraph-prebuilt` provides an implementation of a tool-calling ReAct-style agent — `create_react_agent`."

```mermaid
graph TD
    A[Graph run<br/>invoke/stream/batch] --> B[Pregel executor<br/>per superstep]
    B --> C[Channels<br/>state values]
    B --> D[Checkpointer<br/>BaseCheckpointSaver]
    B --> E[Store<br/>BaseStore]
    C --> F[Channel versions]
    F --> G[Checkpoint tuple<br/>v, ts, id, channel_values, channel_versions, versions_seen]
    G --> H[Serde<br/>JsonPlusSerializer / msgpack]
    H --> I[Backend<br/>InMemory / SQLite / Postgres / custom]
    E --> J[(Cross-thread<br/>long-term memory)]
    I --> K[(Per-thread<br/>checkpoint history)]
    style H fill:#fdf6b2,stroke:#333
    style D fill:#cde,stroke:#333
    style E fill:#cde,stroke:#333
```

## Checkpointing

### Concepts

| Concept | Description |
|---|---|
| **Checkpoint** | A snapshot of the graph state at a given point in time. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — "Checkpoint is a snapshot of the graph state at a given point in time." |
| **Checkpoint tuple** | An object containing the checkpoint and the associated config, metadata, and pending writes. |
| **Thread** | A unique ID assigned to a series of checkpoints. Always requires `thread_id`; optionally accepts `checkpoint_id` to resume from a specific point. |
| **Pending writes** | Intermediate writes stored when a superstep partially fails; successful nodes are not re-run on resume. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — "When a graph node fails mid-execution at a given superstep, LangGraph stores pending checkpoint writes from any other nodes that completed successfully at that superstep…" |
| **Superstep** | A single round of node execution that produces one checkpoint. |

A valid thread config is just a `configurable` dict:

```python
{"configurable": {"thread_id": "1"}}                                   # latest checkpoint
{"configurable": {"thread_id": "1",
                  "checkpoint_id": "0c62ca34-ac19-445d-bbb0-5b4984975b2a"}}  # specific point
```

Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — "You must pass these when invoking the graph as part of the configurable part of the config, e.g."

### The `BaseCheckpointSaver` Interface

Every checkpointer must conform to `langgraph.checkpoint.base.BaseCheckpointSaver`. The required surface is:

| Method | Purpose |
|---|---|
| `.put` | Store a checkpoint with its configuration and metadata. |
| `.put_writes` | Store intermediate writes (pending writes) linked to a checkpoint. |
| `.get_tuple` | Fetch a checkpoint tuple for a given configuration (`thread_id` + optional `checkpoint_id`). |
| `.list` | List checkpoints that match a configuration and filter criteria. |
| `.delete_thread()` | Delete all checkpoints and writes associated with a thread. |
| `.get_next_version()` | Generate the next version ID for a channel. The base implementation returns an integer sequence starting from 1, but may be overridden. |

For **async** graph execution (`.ainvoke`, `.astream`, `.abatch`) the checkpointer must implement async counterparts: `.aput`, `.aput_writes`, `.aget_tuple`, `.alist`, and `.adelete_thread()`. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — "If the checkpointer will be used with asynchronous graph execution (i.e. executing the graph via `.ainvoke`, `.astream`, `.abatch`), checkpointer must implement asynchronous versions of the above methods…"

### Bundled Implementations

LangGraph ships three reference implementations plus a test-harness package:

| Package | Backend | Notes |
|---|---|---|
| `langgraph.checkpoint.memory.InMemorySaver` | Process memory | Default; useful for tests and short-lived demos. |
| `langgraph.checkpoint.sqlite.{Sync,Async}SqliteSaver` | SQLite | Embedded, single-file persistence. |
| `langgraph.checkpoint.postgres.{Sync,Async}PostgresSaver` | PostgreSQL | Production-grade persistence, supports pooling and concurrent workers. |
| `langgraph-checkpoint-conformance` | n/a (test suite) | Validates that a custom `BaseCheckpointSaver` correctly implements the storage contract. |

Sources: [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md), [libs/checkpoint-postgres/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-postgres/README.md), [libs/checkpoint-conformance/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-conformance/README.md).

#### In-Memory Example

```python
from langgraph.checkpoint.memory import InMemorySaver

write_config = {"configurable": {"thread_id": "1", "checkpoint_ns": ""}}
read_config  = {"configurable": {"thread_id": "1"}}

checkpointer = InMemorySaver()
checkpoint = {
    "v": 4,
    "ts": "2024-07-31T20:14:19.804150+00:00",
    "id": "1ef4f797-8335-6428-8001-8a1503f9b875",
    "channel_values": {"my_key": "meow", "node": "node"},
    "channel_versions": {"__start__": 2, "my_key": 3, "start:node": 3, "node": 3},
    "versions_seen": {
        "__input__": {},
        "__start__": {"__start__": 1},
        "node": {"start:node": 2},
    },
}

checkpointer.put(write_config, checkpoint, {}, {})
checkpointer.get(read_config)
list(checkpointer.list(read_config))
```

Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — usage section.

#### SQLite (sync and async)

```python
# Sync
from langgraph.checkpoint.sqlite import SqliteSaver
with SqliteSaver.from_conn_string(":memory:") as checkpointer:
    checkpointer.put(write_config, checkpoint, {}, {})

# Async
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
    await checkpointer.aput(write_config, checkpoint, {}, {})
    [c async for c in checkpointer.alist(read_config)]
```

Source: [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md).

#### Postgres (sync and async)

The Postgres checkpointer exposes the same `from_conn_string` factory pattern and supports high-concurrency workloads. The `AsyncPostgresSaver` is the production choice for `astream`/`ainvoke` graphs:

```python
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver

async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
    await checkpointer.aput(write_config, checkpoint, {}, {})
    [c async for c in checkpointer.alist(read_config)]
```

Source: [libs/checkpoint-postgres/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-postgres/README.md).

> **Community pitfall — SSL errors on Postgres.** Issue [#3716](https://github.com/langchain-ai/langgraph/issues/3716) reports a `psycopg.OperationalError: sending query and params failed: SSL error: bad length` that recurs across multiple `langgraph-checkpoint-postgres` versions. The thread is long-running and concentrates on transport/SSL configuration, indicating that **checkpointer-level errors are frequently caused by connection-driver issues rather than the storage contract itself** — diagnose the driver first before suspecting the saver.

### Conformance Test Suite

`langgraph-checkpoint-conformance` is a separate package that validates whether a `BaseCheckpointSaver` correctly implements the contract — covering blob round-trips, metadata preservation, namespace isolation, incremental channel updates, and prune/delete semantics. Source: [libs/checkpoint-conformance/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-conformance/README.md).

#### Registration and execution

```python
import asyncio
from langgraph.checkpoint.conformance import checkpointer_test, validate

@checkpointer_test(name="MyCheckpointer")
async def my_checkpointer():
    saver = MyCheckpointer(...)
    yield saver                # cleanup runs after yield

async def main():
    report = await validate(my_checkpointer)
    report.print_report()
    assert report.passed_all_base()

asyncio.run(main())
```

You can also use it as a pytest fixture and assert on the report at the end of each test.

#### Capabilities

The suite distinguishes **base** (required) from **extended** (optional, auto-detected) capabilities. From the README:

| Capability | Required | Method |
|---|---|---|
| `put` | yes | `aput` |
| `put_writes` | yes | `aput_writes` |
| `get_tuple` | yes | `aget_tuple` |
| … | … | … |

#### Selective execution

```python
# Skip a capability entirely
@checkpointer_test(name="MyCheckpointer", skip_capabilities={"prune"})
async def my_checkpointer():
    yield MyCheckpointer(...)

# Run only a subset
report = await validate(my_checkpointer, capabilities={"put", "list"})

# One-time lifespan for expensive setup (e.g. creating a database)
async def db_lifespan():
    await create_database()
    yield
    await drop_database()

@checkpointer_test(name="PostgresSaver", lifespan=db_lifespan)
async def pg_checkpointer():
    async with PostgresSaver.from_conn_string(CONN_STRING) as saver:
        yield saver
```

Source: [libs/checkpoint-conformance/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-conformance/README.md).

## Serialization (Serde)

### Protocol and Default Implementation

The checkpoint library defines a serialization/deserialization protocol and ships a default implementation, `langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer`, which handles "a wide variety of types, including LangChain and LangGraph primitives, datetimes, enums and more." Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md).

### Security: Restrict Deserialization

> **IMPORTANT — Checkpoint deserialization security.** "By default the serializer allows any Python type found in checkpoint data. New applications should set the environment variable `LANGGRAPH_STRICT_MSGPACK=true` or pass an explicit `allowed_msgpack_modules` list to `JsonPlusSerializer` to restrict deserialization to known-safe types." Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md).

This is a deliberate hardening step for production: a permissive serde layer is convenient in development but is a deserialization-time attack surface when checkpoint bytes come from an untrusted source. The two recommended mitigations are:

1. Set `LANGGRAPH_STRICT_MSGPACK=true` in the environment.
2. Or pass an explicit allow-list: `JsonPlusSerializer(allowed_msgpack_modules=[...])`.

### Common Serialization Failure Modes

> **Community bug — `Send` is not msgpack-serializable.** Issue [#5891](https://github.com/langchain-ai/langgraph/issues/5891) reports `TypeError: Type is not msgpack serializable: Send` when using `create_react_agent` with a tool that uses `BaseStore`. This is a concrete case where a graph control-flow primitive (`Send`, used for map-reduce style fan-out) is being held in a value that the serde layer must encode. The fix is to keep transient `Send` objects out of long-lived channel state — only return them from routing functions, never store them in fields persisted to a checkpoint.

> **Community error — `InvalidUpdateError`.** Issue [#740](https://github.com/langchain-ai/langgraph/issues/740) raises `langgraph.errors.InvalidUpdateError: Must write to at least one of ['input', 'plan', 'past_steps', 'response']`. Although framed as a routing error, the underlying cause is usually that a node did not produce an update for one of the declared channels. When using a checkpointer, that channel list also determines what the next checkpoint will persist — so the error is closely tied to both the channel contract and the serde contract.

```mermaid
graph TD
    A[Node returns dict] --> B{All declared channels<br/>have a value?}
    B -- No --> C[InvalidUpdateError<br/>raised at superstep boundary]
    B -- Yes --> D[Reducer applies update]
    D --> E[Channel version bumped]
    E --> F[Checkpointer.put writes<br/>serialized checkpoint]
    F --> G[JsonPlusSerializer<br/>default]
    G --> H[msgpack bytes]
    style C fill:#fbb,stroke:#900
    style G fill:#fdf6b2,stroke:#333
```

## Stores (`BaseStore`)

### Role vs. Checkpointer

A `checkpointer` is **per-thread** — its `thread_id` scopes every read and write, and it primarily drives durable execution, replay, and human-in-the-loop. A `store` (typed as `BaseStore`) is **cross-thread long-term memory**: a key/value namespace that agents use for facts that should outlive any single conversation thread. Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md) — `create_react_agent` documents `BaseStore` as a separate persistence primitive.

In the prebuilt agent:

```python
from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic

def search(query: str) -> str: ...
tools = [search]
model = ChatAnthropic(model="claude-3-7-sonnet-latest")
app = create_react_agent(model, tools)
app.invoke({"messages": [{"role": "user", "content": "what is the weather in sf"}]})
```

Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md).

### What `BaseStore` Provides

- A namespaced key/value interface, independent of any specific `thread_id`.
- A separation between **working memory** (the in-flight graph state, checkpointed per superstep) and **long-term memory** (the store). Source: [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md) — "Create truly stateful agents with both short-term working memory for ongoing reasoning and long-term persistent memory across sessions."
- Integration points inside prebuilt agents — a tool can read or write a `BaseStore` from inside a `create_react_agent` tool call.

### Known Interaction with Checkpointing

Issue [#5891](https://github.com/langchain-ai/langgraph/issues/5891) demonstrates a subtle interaction: a tool that **uses** a `BaseStore` and that runs inside a `create_react_agent` can trigger a `TypeError: Type is not msgpack serializable: Send` from the checkpoint serde layer. The store is not the serializer's direct target — the *Send* object that ended up in persisted state is. Practical guidance:

- Never persist `Send` objects in a field that is written to a checkpoint.
- Treat transient Pregel control-flow objects (`Send`, `Command` payloads intended for routing only) as ephemeral.
- When a custom reducer returns a `Send`, ensure the reducer's output is consumed by a routing edge and is not stored as a state field.

## Relationship to the v1 Roadmap and Context API

Two high-engagement community threads shape near-term evolution of this surface area:

- **Issue [#4973](https://github.com/langchain-ai/langgraph/issues/4973) — v1 roadmap.** The maintainers explicitly call out the low-level `StateGraph` API and related tooling as the focus, which includes the checkpointing, serde, and store layers covered here. Expect contract refinements to land in `1.x`.
- **Issue [#5023](https://github.com/langchain-ai/langgraph/issues/5023) — `config.configurable` → `context` API.** A proposed change moves immutable context out of the runtime config (`config.configurable`) into a first-class `context` parameter passed at invoke time. The change does not remove the `thread_id`/`checkpoint_id` use of `config.configurable` — those are still required to address a checkpointer — but it does affect how you pass non-serializable or per-run values that previously had to live alongside `thread_id` in `configurable`.

> The persistence contract described on this page — `BaseCheckpointSaver` methods, `JsonPlusSerializer` defaults, the security note on strict msgpack, and `BaseStore` as a separate primitive — is the contract as of the `langgraph==1.2.4` release (latest in the community context at time of writing).

## Common Failure Modes and Diagnostics

| Symptom | Likely cause | Where to look |
|---|---|---|
| `TypeError: Type is not msgpack serializable: Send` | A transient control-flow value was stored in a checkpointed field. | Issue [#5891](https://github.com/langchain-ai/langgraph/issues/5891); check node return values and reducers. |
| `langgraph.errors.InvalidUpdateError: Must write to at least one of [...]` | A node returned without writing to a declared channel, or a reducer swallowed the update. | Issue [#740](https://github.com/langchain-ai/langgraph/issues/740); align the channel list with the node return shape. |
| `psycopg.OperationalError: sending query and params failed: SSL error: bad length` | Connection-driver/SSL issue in `langgraph-checkpoint-postgres`, not a storage-contract bug. | Issue [#3716](https://github.com/langchain-ai/langgraph/issues/3716); check pool/SSL settings before debugging the saver. |
| Restored state is missing types or contains wrong classes | `JsonPlusSerializer` was instantiated without an allow-list, or `LANGGRAPH_STRICT_MSGPACK` is not set. | Hardening section of [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md). |
| Custom checkpointer behaves differently between sync and async runs | Missing async methods (`.aput`, `.aput_writes`, `.aget_tuple`, `.alist`, `.adelete_thread()`). | Interface table in [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md). |
| Long-running suite has expensive setup that runs per test | Use the conformance suite's `lifespan` parameter for one-time setup. | [libs/checkpoint-conformance/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-conformance/README.md). |

## See Also

- [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md) — checkpointing concepts, `BaseCheckpointSaver`, serde, security note.
- [libs/checkpoint-conformance/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-conformance/README.md) — conformance test suite for custom checkpointers.
- [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md) — embedded SQLite implementation.
- [libs/checkpoint-postgres/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-postgres/README.md) — Postgres implementation (sync and async).
- [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md) — `create_react_agent` and the role of `BaseStore`.
- [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md) — top-level feature overview (durable execution, memory, human-in-the-loop).
- Issue [#5891](https://github.com/langchain-ai/langgraph/issues/5891), [#740](https://github.com/langchain-ai/langgraph/issues/740), [#3716](https://github.com/langchain-ai/langgraph/issues/3716), [#4973](https://github.com/langchain-ai/langgraph/issues/4973), [#5023](https://github.com/langchain-ai/langgraph/issues/5023) — community context that informed this page.

---

<a id='page-4'></a>

## CLI, Python SDK, and Deployment Workflows

### Related Pages

Related topics: [Core Graph Construction and Runtime](#page-1), [Checkpointing, Serialization, and Stores](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
- [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)
- [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)
- [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)
- [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md)
- [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py)
- [libs/cli/js-examples/package.json](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/package.json)
- [libs/cli/js-examples/src/agent/state.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)
- [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md)
</details>

# CLI, Python SDK, and Deployment Workflows

LangGraph ships a multi-package developer toolchain that spans the command line, a Python client SDK, and a production deployment surface. Together these packages let developers **scaffold**, **develop**, **deploy**, and **remotely drive** stateful agent graphs. This page documents the `langgraph-cli` and `langgraph-sdk` packages, the deployment workflows they enable, and known limitations surfaced by the community.

Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md) · Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

---

## 1. Overview and Scope

The LangGraph repository is organized as a monorepo. The two packages most directly involved in CLI and deployment workflows are:

| Package | Role | Entry point |
| --- | --- | --- |
| `langgraph-cli` | Project scaffolding, local dev server, Docker build & launch | `langgraph` command |
| `langgraph-sdk` | Python client for the LangSmith Deployment REST API | `langgraph_sdk.get_client()` |
| `langgraph` (core) | The runtime that the CLI serves and the SDK calls | `from langgraph.graph import StateGraph` |
| `langgraph-checkpoint` | Persistence interface shared by local and remote deployments | `BaseCheckpointSaver` |

Source: [README.md](https://github.com/langchain-ai/langgraph/blob/main/README.md) · Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

The high-level relationship between these packages is:

```mermaid
graph TD
    Dev[Developer] -->|writes graph| Code[StateGraph code]
    Code -->|registered in langgraph.json| Config[Config file]
    Config --> CLI[langgraph-cli]
    CLI -->|langgraph dev| Local[In-process API server]
    CLI -->|langgraph up / build| Docker[Docker container]
    Docker --> Deploy[Remote LangSmith Deployment]
    Deploy -->|REST + SSE / WebSocket| SDK[langgraph-sdk]
    SDK --> App[Client application]
    Local -->|REST + SSE| SDK
    SDK --> Checkpoint[BaseCheckpointSaver]
    Checkpoint --> Store[(Postgres / SQLite / external store)]
```

Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md) · Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

---

## 2. LangGraph CLI (`langgraph-cli`)

The `langgraph-cli` package is the official command-line interface for creating, developing, and deploying LangGraph applications. Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)

### 2.1 Installation

The CLI is distributed as a regular Python package and an optional "inmem" extra that enables hot reloading during local development.

```bash
pip install langgraph-cli
pip install "langgraph-cli[inmem]"   # dev mode with hot reloading
```

Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)

### 2.2 Commands

| Command | Purpose | Notable flags |
| --- | --- | --- |
| `langgraph new [PATH] --template NAME` | Scaffold a new project from a template | `--template` |
| `langgraph dev` | Run the API server in dev mode with hot reload | `--host`, `--port`, `--no-reload`, `--debug-port`, `--no-browser`, `-c/--config` |
| `langgraph up` | Launch the API server in Docker | `-p/--port`, `--wait`, `--watch`, `--verbose`, `-c/--config`, `-d/--docker-compose` |
| `langgraph build` | Build a Docker image for the application | `-t` (tag) |

Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)

### 2.3 Configuration file (`langgraph.json`)

Every CLI command reads a configuration file (default: `langgraph.json`) that lists the graphs the server should expose. The `langgraph new` flow writes a starter config and a starter `graph.py` such as the one shipped in the `uv-examples/simple` template:

```python
from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import AIMessage, BaseMessage
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]

def call_model(state: State) -> dict:
    return {"messages": [AIMessage(content="Hello from simple uv agent!")]}

def should_continue(state: State):
    if len(state["messages"]) > 0:
        return END
    return "call_model"

workflow = StateGraph(State)
workflow.add_node("call_model", call_model)
workflow.add_edge(START, "call_model")
workflow.add_conditional_edges("call_model", should_continue)

graph = workflow.compile()
```

Source: [libs/cli/uv-examples/simple/src/agent/graph.py](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/uv-examples/simple/src/agent/graph.py)

### 2.4 Local development workflow

The typical inner loop is:

```mermaid
graph LR
    A[Edit graph.py] --> B[langgraph dev]
    B --> C[Hot reload]
    C --> D{Curl / SDK call}
    D -->|Bug| A
    D -->|OK| E[langgraph build]
    E --> F[langgraph up]
    F --> G[Production LangSmith Deployment]
```

`langgraph dev` defaults to `127.0.0.1:2024` and is the recommended surface for iterating on graph logic. `langgraph up` is the bridge to a containerized, production-like runtime and defaults to port `8123`. Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)

### 2.5 JavaScript / TypeScript templates

The CLI also scaffolds TypeScript projects. The JS template registers `my_app/graph.ts` as the entry point and pins `@langchain/langgraph` and `@langchain/core` as dependencies:

```json
{
  "name": "example-graph",
  "version": "0.0.1",
  "main": "my_app/graph.ts",
  "dependencies": {
    "@langchain/core": "^1.1.48",
    "@langchain/langgraph": "^1.3.3"
  }
}
```

Source: [libs/cli/js-examples/package.json](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/package.json)

The corresponding state declaration uses an `Annotation` with a `messagesStateReducer`, identical in spirit to the Python `add_messages` reducer:

```typescript
messages: Annotation<BaseMessage[], BaseMessageLike[]>({
  reducer: messagesStateReducer,
  default: () => [],
}),
```

Source: [libs/cli/js-examples/src/agent/state.ts](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/js-examples/src/agent/state.ts)

---

## 3. Python SDK (`langgraph-sdk`)

`langgraph-sdk` is the Python client for the LangSmith Deployment REST API. It is published as `langgraph-sdk` on PyPI and is independent of the runtime — the SDK only needs an API server URL. Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

### 3.1 Quick start

```bash
pip install -U langgraph-sdk
```

```python
from langgraph_sdk import get_client

# Local dev server (langgraph dev / langgraph up) is auto-detected
client = get_client()

assistants = await client.assistants.search()
agent = assistants[0]

thread = await client.threads.create()

input = {"messages": [{"role": "human", "content": "what's the weather in la"}]}

async for chunk in client.runs.stream(thread["thread_id"], agent["assistant_id"], input=input):
    print(chunk)
```

Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

### 3.2 Core resource surface

The SDK exposes a small set of namespaced resources. The README snippet above exercises three of them:

| Resource | Sample method | Purpose |
| --- | --- | --- |
| `client.assistants` | `.search()` | List or query deployed graphs |
| `client.threads` | `.create()` | Create a new conversation thread (state container) |
| `client.runs` | `.stream(thread_id, assistant_id, input=...)` | Stream a run against a thread |

Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

> [!NOTE]
> When you register a graph in `langgraph.json`, the deployment auto-creates an assistant, which is why `assistants[0]` is typically the agent you just registered. Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

### 3.3 Synchronous vs. asynchronous clients

The SDK ships both async and sync variants. They differ in the streaming transport they can use, which is a deployment-relevant consideration:

| Client | Streaming transport | Notes |
| --- | --- | --- |
| `AsyncThreadStream` (async) | Server-Sent Events **or** WebSockets | WebSocket transport requires `websockets>=14` |
| `SyncThreadStream` (sync) | Server-Sent Events only | No WebSocket support |

Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

```mermaid
graph TD
    App[Client code] --> Decide{async?}
    Decide -->|yes| A[AsyncLangGraphClient]
    Decide -->|no| S[SyncLangGraphClient]
    A --> Transport1{Transport?}
    Transport1 -->|SSE| SSE1[EventSource HTTP]
    Transport1 -->|WebSocket| WS1[websockets>=14]
    S --> SSE2[EventSource HTTP]
    SSE1 --> Server[(LangGraph API server)]
    WS1 --> Server
    SSE2 --> Server
```

Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

### 3.4 Known limitations (from the SDK README)

The SDK's own README lists three explicit caveats that any deployment automation should respect:

1. **WebSocket transport** requires `websockets>=14` and is only available on the async client. The sync client uses SSE exclusively.
2. **`thread.extensions[name]`** opens a new subscription each time the same name is accessed. To avoid duplicate work in a single session, assign the projection to a variable and reuse it.
3. **Sync streaming** drives the lifecycle watcher (described in the README but truncated in the snippet we have).

Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

---

## 4. Deployment Workflows

A "deployment" in LangGraph is a runnable API server that hosts one or more compiled graphs, persists their state, and exposes them through the REST API the SDK consumes. The CLI orchestrates the local-to-remote path, and the SDK is the canonical programmatic interface.

### 4.1 The two-server model

```mermaid
graph TD
    subgraph Local["Local laptop"]
        Code[graph.py] --> Json[langgraph.json]
        Json --> Dev[langgraph dev<br/>127.0.0.1:2024]
    end
    subgraph Host["Docker host / cloud"]
        Json --> Up[langgraph up<br/>:8123]
        Up --> Image[langgraph build image]
    end
    Dev -.dev only.-> SDK
    Up --> SDK[langgraph-sdk]
    SDK --> App[End-user application]
```

Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md) · Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)

### 4.2 Persistence via checkpointers

Both local and remote deployments share the same persistence interface. Threads are identified by `configurable.thread_id`, and individual checkpoints can be addressed by `configurable.checkpoint_id`:

```python
{"configurable": {"thread_id": "1"}}
{"configurable": {"thread_id": "1", "checkpoint_id": "0c62ca34-ac19-445d-bbb0-5b4984975b2a"}}
```

Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

Production deployments typically use `langgraph-checkpoint-postgres`, while `langgraph-checkpoint-sqlite` is well suited to local development. The SQLite readme shows the canonical usage pattern (sync and async variants share the same shape):

```python
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver

async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
    # checkpoint contains: v, ts, id, channel_values, channel_versions, versions_seen
    await checkpointer.put(write_config, checkpoint, {}, {})
    await checkpointer.get(read_config)
    async for item in checkpointer.list(read_config):
        ...
```

Source: [libs/checkpoint-sqlite/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-sqlite/README.md)

### 4.3 Pending writes and durable execution

A defining property of LangGraph's runtime is "pending writes". When a superstep partially fails, LangGraph stores the writes from the nodes that did complete, so that on resume those nodes are not re-executed. This is the mechanism that makes the runtime durable across crashes. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

```mermaid
graph TD
    S[Superstep starts] --> N1[Node A]
    S --> N2[Node B]
    S --> N3[Node C]
    N1 --> W1[(pending writes)]
    N2 -->|fails| E[Runtime exception]
    N3 --> W1
    E --> Resume[Resume from superstep]
    W1 --> Resume
    Resume --> N1x[Skip A - already written]
    Resume --> N3x[Skip C - already written]
    Resume --> N2r[Rerun B only]
```

Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

### 4.4 Prebuilt components used in deployments

The `langgraph-prebuilt` library is bundled with `langgraph` and provides high-level building blocks commonly shipped in deployed graphs. Two examples are relevant to deployment workflows:

- **`create_react_agent`** — a tool-calling ReAct-style agent constructor. The prebuilt README demonstrates wiring it with `ChatAnthropic` and a `search` tool, then invoking it with a message dict. Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

  ```python
  from langchain_anthropic import ChatAnthropic
  from langgraph.prebuilt import create_react_agent

  def search(query: str):
      """Call to surf the web."""
      if "sf" in query.lower() or "san francisco" in query.lower():
          return "It's 60 degrees and foggy."
      return "It's 90 degrees and sunny."

  app = create_react_agent(ChatAnthropic(model="claude-3-7-sonnet-latest"), [search])
  app.invoke({"messages": [{"role": "user", "content": "what is the weather in sf"}]})
  ```

- **`ValidationNode`** — a node that validates tool calls against a Pydantic schema before they run. Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

- **Agent Inbox schemas** — `HumanInterrupt` and `HumanResponse` dataclasses plus the `interrupt()` helper enable human-in-the-loop patterns that pair naturally with deployed long-running threads. Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

> [!IMPORTANT]
> The prebuilt README explicitly states that `langgraph-prebuilt` is meant to be bundled with `langgraph`; it should not be installed directly. Source: [libs/prebuilt/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/prebuilt/README.md)

---

## 5. Security and Configuration Notes

### 5.1 Checkpoint deserialization

The default checkpoint serializer (`JsonPlusSerializer`) is permissive. The checkpoint README recommends the following for new applications:

> **Checkpoint deserialization security:** By default the serializer allows any Python type found in checkpoint data. New applications should set the environment variable `LANGGRAPH_STRICT_MSGPACK=true` or pass an explicit `allowed_msgpack_modules` list to `JsonPlusSerializer` to restrict deserialization to known-safe types.

Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

### 5.2 Configuration

A typical deployment's configurable surface:

| Knob | Where | Effect |
| --- | --- | --- |
| `LANGGRAPH_STRICT_MSGPACK` | Environment | Restricts deserializable types when loading checkpoints |
| `--host`, `--port` | `langgraph dev` flags | Bind address for local dev server (default `127.0.0.1:2024`) |
| `--config` / `-c` | All CLI commands | Path to `langgraph.json` (default `langgraph.json`) |
| `--docker-compose` / `-d` | `langgraph up` | Additional services file |
| `configurable.thread_id` | SDK call | Selects the conversation thread |
| `configurable.checkpoint_id` | SDK call | Selects a specific checkpoint within a thread |
| `allowed_msgpack_modules` | `JsonPlusSerializer(...)` | Explicit allowlist of importable types |

Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md) · Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

---

## 6. Common Failure Modes Seen in the Community

The community issues surfaced alongside the latest release highlight recurring pain points that map directly onto CLI, SDK, and deployment workflows.

### 6.1 Context management (issue #5023)

A long-standing source of developer confusion is passing immutable context into a run. The team is actively soliciting feedback on a `config.configurable` → `context` API rename. The proposal is motivated by the fact that mixing thread configuration with ad-hoc context keys is one of the most error-prone parts of the SDK today. Community context: `Top Community Issues #5023`.

**Workaround until the new API lands:** keep thread identifiers (`thread_id`, `checkpoint_id`) in `config.configurable` and pass everything else (user IDs, feature flags, tenant metadata) in the same `config.configurable` namespace, naming your keys to make the distinction explicit.

### 6.2 `TypeError: Type is not msgpack serializable: Send` (issue #5891)

When using `create_react_agent` with a tool that uses `BaseStore`, the runtime may emit `TypeError: Type is not msgpack serializable: Send`. The checkpointer's serializer cannot encode the in-flight `Send` object. Community context: `Top Community Issues #5891`.

**Mitigations:**

- Enable strict msgpack deserialization (`LANGGRAPH_STRICT_MSGPACK=true`) and supply an explicit `allowed_msgpack_modules` list so the serializer rejects unencodable objects early. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)
- Make sure tool outputs returned via `BaseStore` are JSON-serializable before they reach the next superstep.

### 6.3 `InvalidUpdateError` (issue #740)

`langgraph.errors.InvalidUpdateError: Must write to at least one of ['input', 'plan', 'past_steps', 'response']` is a symptom of a node returning an empty dict (or one that does not intersect with the graph's declared channels). The runtime cannot advance a superstep without at least one write. Community context: `Top Community Issues #740`.

**Mitigations:**

- Audit each node to ensure it always returns a non-empty dict that contains at least one of the state channels declared on the `StateGraph`.
- For early-exit nodes, explicitly `return {"__end__": ...}` or route to `END` instead of returning `{}`.

### 6.4 Postgres SSL errors (issue #3716)

`langgraph-checkpoint-postgres` users have reported intermittent `psycopg.OperationalError: sending query and params failed: SSL error: bad length` across multiple versions. The community thread contains 48 comments tracking workarounds, including pinning the `psycopg` driver version and tuning connection-pool sizes. Community context: `Top Community Issues #3716`.

### 6.5 Release hygiene

`langgraph==1.2.4` is the current release at the time of writing. Notable changes since `1.2.3` include a `langgraph` patch release, a new factory-graph integration test in `sdk-py`, and a backward-compatibility fix for `_on_started` overrides predating `cause`. Source: community context (`Latest Release: langgraph==1.2.4`).

---

## 7. End-to-End Worked Example

Putting the pieces together, a typical end-to-end workflow is:

```mermaid
graph TD
    A[langgraph new PATH --template simple] --> B[Edit src/agent/graph.py]
    B --> C[langgraph dev --port 2024]
    C --> D{Smoke test with curl or SDK}
    D -->|fail| B
    D -->|pass| E[langgraph build -t my-agent:latest]
    E --> F[langgraph up --port 8123]
    F --> G[Configure Postgres checkpointer]
    G --> H[Python service uses langgraph-sdk]
    H --> I[Users interact via threads]
```

Concrete steps:

1. **Scaffold** — `langgraph new ./my-agent --template simple` writes a `langgraph.json` and a starter `graph.py` similar to the snippet in §2.3. Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
2. **Iterate** — `langgraph dev` exposes the graph on `127.0.0.1:2024` with hot reload. Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
3. **Drive from Python** — point `langgraph_sdk.get_client()` at the dev URL and stream runs. Source: [libs/sdk-py/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/sdk-py/README.md)
4. **Containerize** — `langgraph build -t my-agent:latest` produces an image that `langgraph up` will launch. Source: [libs/cli/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/README.md)
5. **Harden** — set `LANGGRAPH_STRICT_MSGPACK=true` and configure a Postgres checkpointer for production. Source: [libs/checkpoint/README.md](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint/README.md)

---

## 8. See Also

- [LangGraph Overview & Core Concepts](https://docs.langchain.com/oss/python/langgraph/overview)
- [Durable Execution](https://docs.langchain.com/oss/python/langgraph/durable-execution)
- [Human-in-the-Loop / Interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts)
- [Memory and Persistence](https://docs.langchain.com/oss/python/langgraph/memory)
- [LangSmith Deployment](https://docs.langchain.com/langsmith/deployments)
- [LangGraph Reference (Python)](https://reference.langchain.com/python/langgraph/)
- [LangGraph.js repository and docs](https://github.com/langchain-ai/langgraphjs)
- [Deep Agents (higher-level package built on LangGraph)](https://docs.langchain.com/oss/python/deepagents/overview)
- [LangChain Forum](https://forum.langchain.com/)

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: langchain-ai/langgraph

Summary: Found 10 structured pitfall item(s), including 1 high/blocking item(s). Top priority: Security or permission risk - Security or permission risk requires verification.

## 1. Security or permission risk - Security or permission risk requires verification

- Severity: high
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_23c4b9aa6f6b4875a15c0b250353c3e2 | https://github.com/langchain-ai/langgraph/issues/6987

## 2. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_1838455940614b8db19df66c6bbccd01 | https://github.com/langchain-ai/langgraph/issues/7989

## 3. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.assumptions | github_repo:676672661 | https://github.com/langchain-ai/langgraph

## 4. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:676672661 | https://github.com/langchain-ai/langgraph

## 5. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: downstream_validation.risk_items | github_repo:676672661 | https://github.com/langchain-ai/langgraph

## 6. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: risks.scoring_risks | github_repo:676672661 | https://github.com/langchain-ai/langgraph

## 7. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_909ae18070e04cbeacc82e6cd02ab90f | https://github.com/langchain-ai/langgraph/issues/7798

## 8. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | cevd_f0e63713a60b42a38bcb16276fc24382 | https://github.com/langchain-ai/langgraph/issues/5672

## 9. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:676672661 | https://github.com/langchain-ai/langgraph

## 10. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Suggested check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | github_repo:676672661 | https://github.com/langchain-ai/langgraph

<!-- canonical_name: langchain-ai/langgraph; human_manual_source: deepwiki_human_wiki -->
