Doramagic Project Pack · Human Manual

langgraph

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:

Core Graph Construction and Runtime

Related topics: Prebuilt Agents, Tools, and Common Errors, Checkpointing, Serialization, and Stores

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 3.1 Python — TypedDict + addmessages

Continue reading this section for the full explanation and source context.

Section 3.2 TypeScript — Annotation.Root

Continue reading this section for the full explanation and source context.

Section 4.1 Adding Nodes

Continue reading this section for the full explanation and source context.

Related topics: Prebuilt Agents, Tools, and Common Errors, Checkpointing, Serialization, and Stores

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.

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.

2. High-Level Architecture

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:

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.

3.2 TypeScript — `Annotation.Root`

The JS example mirrors the pattern using Annotation.Root and messagesStateReducer libs/cli/js-examples/src/agent/state.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:

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:

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 kindPythonTypeScriptSemantics
Staticadd_edge("a", "b").addEdge("a", "b")Always transitions to b after a finishes
Conditionaladd_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.

4.3 End-to-End Construction (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.

4.4 End-to-End Construction (TypeScript)

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.

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 conceptRole
Channel valueThe current per-field value
ReducerFunction that merges an update with the existing value
add_messagesDefault reducer for Sequence[BaseMessage]; handles dedup by ID and append semantics
Last-valueDefault 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.

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

8. Invocation Patterns

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

MethodPurpose
invoke(input, config)Run to completion, return final state
stream(input, config)Yield intermediate state per superstep (or per node with mode)
astream_eventsToken-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:

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.

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:

{"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. The v1 roadmap discussion also covers planned changes to the low-level StateGraph API issue #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. Concrete implementations live in separate packages:

SaverPackageNotes
In-memorylanggraph.checkpoint.memoryDefault in dev, no durability
SQLite (sync & async)langgraph-checkpoint-sqliteLocal single-process persistence; see AsyncSqliteSaver.from_conn_string libs/checkpoint-sqlite/README.md
Postgreslanggraph-checkpoint-postgresProduction / multi-replica; known to have SSL negotiation issues in some versions that are tracked in the community issue #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.

11. Prebuilt Components on Top of the Core

The prebuilt library layers high-level abstractions on the same runtime 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. Setting LANGGRAPH_STRICT_MSGPACK=true typically works around it by routing through a stricter code path.

12. Common Failure Modes

SymptomLikely causeWhere 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 schemaVerify the return value of each node; check the schema in State issue #740
TypeError: Type is not msgpack serializable: SendNon-serializable object reached the checkpoint layerRestrict via LANGGRAPH_STRICT_MSGPACK=true or allowed_msgpack_modules issue #5891
psycopg.OperationalError: SSL error: bad length (postgres)SSL / libpq mismatch in some versions of langgraph-checkpoint-postgresTrack against pinned versions and the open thread issue #3716
Channel value lost after parallel branchesNo reducer on the channel, so last-writer-winsAdd 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:

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.

See Also

Source: https://github.com/langchain-ai/langgraph / Human Manual

Prebuilt Agents, Tools, and Common Errors

Related topics: Core Graph Construction and Runtime, Checkpointing, Serialization, and Stores

Section Related Pages

Continue reading this section for the full explanation and source context.

Section createreactagent

Continue reading this section for the full explanation and source context.

Section When to reach past the prebuilt

Continue reading this section for the full explanation and source context.

Section ToolNode

Continue reading this section for the full explanation and source context.

Related topics: Core Graph Construction and Runtime, Checkpointing, Serialization, and Stores

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

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:

ComponentModulePurpose
create_react_agentlanggraph.prebuilt.chat_agent_executorAssemble a tool-calling ReAct agent graph from a model + tools
ToolNodelanggraph.prebuilt.tool_nodeExecute tool calls emitted by a chat model
ValidationNodelanggraph.prebuilt.tool_validatorValidate tool arguments against a Pydantic schema before execution
HumanInterrupt / HumanResponselanggraph.prebuilt.interruptSchemas for the Agent Inbox human-in-the-loop protocol

Source: libs/prebuilt/README.md:1-12

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

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

#### 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].

#### State shape

FieldTypeReducerDefaultNotes
messagesBaseMessage[] (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

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

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

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

`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].

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

ToolNode vs. ValidationNode

ConcernToolNodeValidationNode
Runs the tool❌ (delegates to ToolNode internally for valid calls)
Validates args with Pydantic
Returns validation errors to the LLMn/a✅ (as ToolMessage)
Typical useTrusted, well-typed toolsUntrusted user input or open-ended tool sets

Source: libs/prebuilt/README.md:32-77

Agent Inbox and Human-in-the-Loop

The prebuilt layer ships the schemas used by the 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].

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

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

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 and the Pregel validator at 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; community discussion: GitHub issue #5023 (14 comments)].

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

Mapping error → component

ErrorMost likely layerFirst place to look
InvalidUpdateError: Must write to at least one of [...]Pregel channel validationState schema and node return values
TypeError: Type is not msgpack serializable: SendCheckpointer serializationTools that close over BaseStore / non-serializable objects
psycopg.OperationalError ... SSL error: bad lengthlanggraph-checkpoint-postgres transportConnection URL SSL mode and driver choice
KeyError on config["configurable"][...]Graph runtime configNamespacing 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]:

CommandDefault portReloadBrowserConfig
langgraph dev2024✅ (unless --no-reload)✅ (unless --no-browser)langgraph.json
langgraph up8123 (Docker)--watchn/alanggraph.json, optional -d compose
langgraph buildn/an/an/a-t tag

Source: libs/cli/README.md:13-56

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

Usage Patterns

Minimal tool-calling agent

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

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

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

Common Failure Modes (Cheat Sheet)

FailureRoot causeMitigation
InvalidUpdateError: Must write to at least one of [...]Node returned delta missing all expected channelsMake every node return at least one channel key; align subgraph outputs with parent channels
TypeError: Type is not msgpack serializable: SendTool 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 lengthMismatched sslmode / proxy re-encryptionMatch sslmode to server; use the async/sync saver that matches your event loop
KeyError on config["configurable"][...]Key collision with LangGraph-reserved namespacingNamespace your keys (config["configurable"]["my_app.user_id"]); track the proposed context API
Agent "loops forever" on a tool errorTool raises an unhandled exceptionCatch exceptions inside the tool and return a string error; consider ValidationNode
Checkpoint corruption after upgradeSerializer/version mismatchUse 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; libs/langgraph/langgraph/pregel/_validate.py.

See Also

Sources: GitHub issues #740, #5891, #3716, #5023; libs/langgraph/langgraph/errors.py; libs/langgraph/langgraph/pregel/_validate.py.

Checkpointing, Serialization, and Stores

Related topics: Core Graph Construction and Runtime, CLI, Python SDK, and Deployment Workflows

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Concepts

Continue reading this section for the full explanation and source context.

Section The BaseCheckpointSaver Interface

Continue reading this section for the full explanation and source context.

Section Bundled Implementations

Continue reading this section for the full explanation and source context.

Related topics: Core Graph Construction and Runtime, CLI, Python SDK, and Deployment Workflows

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 — "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 — "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 — "langgraph-prebuilt provides an implementation of a tool-calling ReAct-style agent — create_react_agent."
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

ConceptDescription
CheckpointA snapshot of the graph state at a given point in time. Source: libs/checkpoint/README.md — "Checkpoint is a snapshot of the graph state at a given point in time."
Checkpoint tupleAn object containing the checkpoint and the associated config, metadata, and pending writes.
ThreadA unique ID assigned to a series of checkpoints. Always requires thread_id; optionally accepts checkpoint_id to resume from a specific point.
Pending writesIntermediate writes stored when a superstep partially fails; successful nodes are not re-run on resume. Source: 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…"
SuperstepA single round of node execution that produces one checkpoint.

A valid thread config is just a configurable dict:

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

Source: 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:

MethodPurpose
.putStore a checkpoint with its configuration and metadata.
.put_writesStore intermediate writes (pending writes) linked to a checkpoint.
.get_tupleFetch a checkpoint tuple for a given configuration (thread_id + optional checkpoint_id).
.listList 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 — "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:

PackageBackendNotes
langgraph.checkpoint.memory.InMemorySaverProcess memoryDefault; useful for tests and short-lived demos.
langgraph.checkpoint.sqlite.{Sync,Async}SqliteSaverSQLiteEmbedded, single-file persistence.
langgraph.checkpoint.postgres.{Sync,Async}PostgresSaverPostgreSQLProduction-grade persistence, supports pooling and concurrent workers.
langgraph-checkpoint-conformancen/a (test suite)Validates that a custom BaseCheckpointSaver correctly implements the storage contract.

Sources: libs/checkpoint-sqlite/README.md, libs/checkpoint-postgres/README.md, libs/checkpoint-conformance/README.md.

#### In-Memory Example

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 — usage section.

#### SQLite (sync and async)

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

#### 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:

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.

Community pitfall — SSL errors on Postgres. Issue #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.

#### Registration and execution

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:

CapabilityRequiredMethod
putyesaput
put_writesyesaput_writes
get_tupleyesaget_tuple

#### Selective execution

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

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.

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.

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 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 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.
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.mdcreate_react_agent documents BaseStore as a separate persistence primitive.

In the prebuilt agent:

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.

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 — "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 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 — 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 #5023config.configurablecontext 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

SymptomLikely causeWhere to look
TypeError: Type is not msgpack serializable: SendA transient control-flow value was stored in a checkpointed field.Issue #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; align the channel list with the node return shape.
psycopg.OperationalError: sending query and params failed: SSL error: bad lengthConnection-driver/SSL issue in langgraph-checkpoint-postgres, not a storage-contract bug.Issue #3716; check pool/SSL settings before debugging the saver.
Restored state is missing types or contains wrong classesJsonPlusSerializer was instantiated without an allow-list, or LANGGRAPH_STRICT_MSGPACK is not set.Hardening section of libs/checkpoint/README.md.
Custom checkpointer behaves differently between sync and async runsMissing async methods (.aput, .aput_writes, .aget_tuple, .alist, .adelete_thread()).Interface table in libs/checkpoint/README.md.
Long-running suite has expensive setup that runs per testUse the conformance suite's lifespan parameter for one-time setup.libs/checkpoint-conformance/README.md.

See Also

Sources: libs/checkpoint-sqlite/README.md, libs/checkpoint-postgres/README.md, libs/checkpoint-conformance/README.md.

CLI, Python SDK, and Deployment Workflows

Related topics: Core Graph Construction and Runtime, Checkpointing, Serialization, and Stores

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Core Graph Construction and Runtime, Checkpointing, Serialization, and Stores

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 · Source: libs/sdk-py/README.md

Source: https://github.com/langchain-ai/langgraph / Human Manual

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

high Security or permission risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Installation risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Capability evidence risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Maintenance risk requires verification

May increase setup, validation, or first-run risk for the user.

Doramagic Pitfall Log

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
  • 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.
  • Recommended 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
  • 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.
  • Recommended 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
  • Finding: README/documentation is current enough for a first validation pass.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended 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
  • 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.
  • Recommended 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
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended 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
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended 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
  • 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.
  • Recommended 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
  • 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.
  • Recommended 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
  • Finding: issue_or_pr_quality=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended 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
  • Finding: release_recency=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended 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

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 12

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using langgraph with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence