Implementation:Langchain ai Langgraph UntrackedValue Channel
| Knowledge Sources | |
|---|---|
| Domains | Channels, State |
| Last Updated | 2026-02-11 16:00 GMT |
Overview
A channel that stores the last value received but intentionally never checkpoints it, ensuring its state is excluded from persistence and always starts fresh after a checkpoint restore.
Description
The UntrackedValue channel extends `BaseChannel` to provide a last-write-wins value store that explicitly opts out of the checkpointing system. Its `checkpoint()` method always returns the `MISSING` sentinel regardless of whether a value has been set, and its `from_checkpoint()` method always creates an empty channel regardless of the checkpoint input. This means that after a checkpoint restore or graph resumption, the channel will always be in its initial empty state.
Like `EphemeralValue`, the channel supports an optional `guard` parameter (defaulting to `True`). When `guard=True`, the `update()` method raises `InvalidUpdateError` if more than one value is received per step, enforcing single-writer semantics. When `guard=False`, the last value in the update sequence is stored without complaint. Unlike `EphemeralValue`, the channel does not clear on empty updates -- calling `update([])` is a no-op that returns `False`.
The `get()` method raises `EmptyChannelError` when no value has been set, and `is_available()` provides a convenient boolean check. The value persists across steps during a single run (it is not cleared by empty updates like `EphemeralValue`), but it is never persisted to the checkpoint store. This makes `UntrackedValue` ideal for runtime-only metadata such as performance counters, debug flags, or transient computation results that should not inflate checkpoint size or survive across runs.
Usage
Use `UntrackedValue` for channels carrying runtime-only state that should never be persisted. Common use cases include internal execution metadata, temporary computation caches within a single run, or debug/profiling data that is irrelevant after the run completes. It keeps checkpoint sizes small by explicitly excluding transient data from serialization.
Code Reference
Source Location
- Repository: Langchain_ai_Langgraph
- File: libs/langgraph/langgraph/channels/untracked_value.py
Signature
class UntrackedValue(Generic[Value], BaseChannel[Value, Value, Value]):
def __init__(self, typ: type[Value], guard: bool = True) -> None: ...
@property
def ValueType(self) -> type[Value]: ...
@property
def UpdateType(self) -> type[Value]: ...
def copy(self) -> Self: ...
def checkpoint(self) -> Value | Any: ...
def from_checkpoint(self, checkpoint: Value) -> Self: ...
def update(self, values: Sequence[Value]) -> bool: ...
def get(self) -> Value: ...
def is_available(self) -> bool: ...
Import
from langgraph.channels.untracked_value import UntrackedValue
I/O Contract
Constructor Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| typ | `type[Value]` | Yes | The type of the value stored in the channel |
| guard | `bool` | No | If `True` (default), raises `InvalidUpdateError` on multi-write per step |
update
| Input | Guard | Output | Description |
|---|---|---|---|
| Empty sequence | N/A | `False` | No-op; value is retained (not cleared) |
| Single value | N/A | `True` | Stores the value |
| Multiple values | `True` | Raises `InvalidUpdateError` | Guard prevents multi-write |
| Multiple values | `False` | `True` | Stores the last value |
Checkpoint Behavior
| Method | Behavior | Description |
|---|---|---|
| `checkpoint()` | Always returns `MISSING` | Value is intentionally excluded from persistence |
| `from_checkpoint(any)` | Always returns empty channel | Ignores checkpoint input entirely |
get
| State | Behavior |
|---|---|
| Value present | Returns the stored value |
| `MISSING` | Raises `EmptyChannelError` |
Usage Examples
from langgraph.channels.untracked_value import UntrackedValue
from langgraph.errors import EmptyChannelError
from langgraph._internal._typing import MISSING
# Create an untracked channel for debug metadata
debug_ch = UntrackedValue(dict, guard=False)
# Write a value
debug_ch.update([{"step_time_ms": 42}])
assert debug_ch.get() == {"step_time_ms": 42}
# Value persists across steps (not cleared by empty update)
debug_ch.update([])
assert debug_ch.get() == {"step_time_ms": 42} # Still available
# But checkpoint always returns MISSING
cp = debug_ch.checkpoint()
assert cp is MISSING
# Restoring from checkpoint always creates empty channel
restored = debug_ch.from_checkpoint(cp)
assert not restored.is_available()
try:
restored.get()
except EmptyChannelError:
print("Untracked value lost after checkpoint restore")
# Guard enforcement
guarded = UntrackedValue(int, guard=True)
guarded.update([42]) # OK
# guarded.update([1, 2]) # Would raise InvalidUpdateError