Commit Graph
7168 Commits
Author SHA1 Message Date
gdibben c4a5cb4d2f Reject --image-pull-secret when a --name lookup finds an existing deployment
--image-pull-secret was only guarded against an existing --deployment-id.
If --name (or the default name) resolved to an existing deployment instead,
CustomerRegistrySource._update silently dropped the secrets: the image
pull secret the user intended never reached the control plane and the
revision could fail with ImagePullBackOff with no warning.
2026-10-14 08:58:15 +01:00
gdibben a751d09a52 feat(cli): add --image-pull-secret for deploying through a private registry
Self-hosted and listener-based deployments created with --push-to or
--image-uri had no way to tell the control plane which Kubernetes
secret to use for pulling the image, so they couldn't deploy at all
when the registry requires authentication.

The control plane's resource_spec already supports image_pull_secrets;
the CLI just never exposed a way to set it. Add a repeatable
--image-pull-secret flag, following the same validation pattern as
--listener-id/--k8s-namespace (only valid when creating a deployment
with --push-to or --image-uri, not on an existing --deployment-id).
2026-10-14 08:41:43 +01:00
Elior Nataf LackritzandGitHub a6731f4367 fix(langgraph): keep a DeltaChannel's value when its field changes to a plain reducer (#9302)
Changing a field from a `DeltaChannel` to a plain reducer, for example
to `Annotated[list, add_messages]`, made threads written under the
`DeltaChannel` read that field as empty. The next run saved its writes
over the empty value, so continuing an old thread replaced its history.
The writes were still stored: the read only rebuilt fields whose current
annotation is a `DeltaChannel`.

- A `BinaryOperatorAggregate` stores its value at every version, so one
with a version and nothing stored was written as a `DeltaChannel`. It's
now rebuilt from the same history walk, one `update` per write, since a
single call would reject a second `Overwrite` and drop the writes after
one.
- `BinaryOperatorAggregate.from_checkpoint` unwraps a stored
`_DeltaSnapshot`.
- The next run saves the full value, so later reads are plain reads, and
switching back to a `DeltaChannel` keeps everything.

Threads written under a plain reducer never walk. A rebuilt read costs
the walk plus one reducer call per write since the last snapshot: with
`add_messages` on `InMemorySaver`, 25 ms at 2,048 messages with a
snapshot every 50 writes, and 0.3 s at 1,998 or 0.9 s at 4,998 messages
with the default 1000. After one run, reads take 6 to 16 ms.

`test_delta_channel_to_plain.py` covers every saver; all but the
plain-thread test fail on main.

JS: langchain-ai/langgraphjs#3017
2026-10-13 20:47:19 -04:00
gethin-langchainandGitHub 8a77332d0d release(cli): 0.4.34 (#9300)
Bumping the CLI to 0.4.34 to cut a release including #9243 (--json on
deploy listeners list).
cli==0.4.34
2026-10-13 16:32:51 +01:00
gethin-langchainandGitHub a1ce197234 feat(cli): add --json to deploy listeners list (#9243)
## Summary

`deploy listeners list` only prints a human-readable table, which a
deploy automation pipeline can't reliably parse to extract a listener's
id for `--listener-id`.

Adds `--json`, which prints the listeners as a JSON array instead of the
table. An empty workspace prints `[]` rather than the "No listeners
found" sentence, so callers never need to special-case the no-results
path when scripting against it.

## Test plan

- [x] `make format && make lint` clean in `libs/cli`
- [x] `test_deploy_listeners_list_command_json` and
`test_deploy_listeners_list_command_json_no_results` in `test_cli.py`,
mirroring the existing table-output test pair
- [x] Full `libs/cli` suite: 529 passed, no regressions
2026-10-13 15:43:03 +01:00
Elior Nataf LackritzandGitHub afbe7e48b1 release(checkpoint-postgres): 3.1.3 (#9287)
Version bump only. No library code changes in this PR.

Unreleased since `checkpointpostgres==3.1.2`:

- #8617 - widen `Store` `put` value type to `Mapping[str, Any]`
- #8556 - derive the delta walk cursor once the target loads
- #8544 - order delta channel replay by task path
- #9217 - validate namespace labels before store dispatch
- #9248 - start the delta walk at the target
- #9262 - treat an empty `checkpoint_id` as the latest in delta history

Follows `checkpoint==4.3.0`, which is already live on PyPI. #8544 raised
the floor to `langgraph-checkpoint>=4.3.0`, so this release needs it.
checkpointpostgres==3.1.3
2026-10-12 22:57:04 +00:00
Elior Nataf LackritzandGitHub 1074714c26 release(checkpoint-sqlite): 3.1.2 (#9288)
Version bump only. No library code changes in this PR.

Unreleased since `checkpointsqlite==3.1.1`:

- #8617 - widen `Store` `put` value type to `Mapping[str, Any]`
- #8557 - walk delta ancestors by parent pointer
- #8544 - order delta channel replay by task path
- #9217 - validate namespace labels before store dispatch
- #9262 - treat an empty `checkpoint_id` as the latest in delta history

Follows `checkpoint==4.3.0`, which is already live on PyPI. #8544 raised
the floor to `langgraph-checkpoint>=4.3.0`, so this release needs it.
sdk==0.4.7 checkpointsqlite==3.1.2
2026-10-12 22:47:17 +00:00
Elior Nataf LackritzandGitHub 740461ed50 release(sdk-py): 0.4.7 (#9289)
Bumps the Python SDK version from 0.4.6 to 0.4.7. A thread stream's run
now ends only on the root graph's `completed` or `failed` event, not a
subgraph's, so `thread.output` no longer reads the state too early and a
run that fails after a subgraph finishes is reported as failed (#9228).
2026-10-12 22:47:05 +00:00
Igor SoarezandGitHub 08a345637f release(langgraph): 1.2.15 (#9283)
Bumps langgraph from 1.2.14 to 1.2.15. It now requires
langgraph-checkpoint 4.3.0 or later (#8544).

Also includes:

- Order delta channel replay by task path (#8544)
- Replay a resumed exit-mode run's delta writes in live order (#9114)
- Give each `bulk_update_state` update its own task id (#9128)
- Stop `astream_events` dropping control/interrupts on v1/v2 (#9219)
- Never store exit-mode delta writes under the null task id (#9229)
- Mark a resume value that fails an interrupt's `response_schema`, so
`ToolNode` can stop swallowing it once langgraph-prebuilt is released
(#9232)
- Don't save a checkpoint past a failed DeltaChannel write (#9235)
- Keep a fork's DeltaChannel snapshot from starting nodes that never ran
(#9264)
- Snapshot a DeltaChannel that an `update_state` Overwrite resets
(#9263)
- Read a run's DeltaChannel input back only on its own checkpoints
(#9260)
- Store an `update_state` input's writes on the checkpoint it updates
(#9258)
- Keep an exit run from a checkpoint the thread moved past out of its
newer branch (#9269)
- Stop at an `interrupt_before` breakpoint when a drain is requested
before it (#9281)
- Save a cached node's writes like a node that ran (#9259)
- Give every message written to a messages DeltaChannel an id (#9275)
1.2.15
2026-10-12 18:34:01 -04:00
b7d053b256 fix(langgraph): give every message written to a messages DeltaChannel an id (#9275)
A DeltaChannel replays its saved writes on every read, and
`_messages_delta_reducer` doesn't fill in missing ids, so the loop gives
messages their ids before saving them (`ensure_message_ids`). That
missed several cases:

- Strings and `(role, content)` tuples, alone or in a list (`[("user",
"hi")]`), and messages inside an `Overwrite` were saved with no id, so
nothing could target them by id, for example `RemoveMessage`. A regular
messages channel gives them ids.
- A raw `Pregel` graph's input to a DeltaChannel got its ids after it
was applied, and none with exit durability or on a new thread; a dict
given as input read back with an id its nodes never saw. A
`Command(update=...)` sent to an older checkpoint got none either.

Now, in a DeltaChannel whose reducer is `_messages_delta_reducer`, every
message-like the reducer accepts becomes a message with an id before the
writes are saved or applied: in `put_writes`, before input is applied,
for a forked `Command`, and in `update_state`. Anything that can't
become a message is left as it is, so it fails where it always has.
Other DeltaChannels keep the rule they had (message objects, and message
dicts in a list, get ids), since they may hold other data and
deepagents' messages channel, which uses its own copy of the reducer,
relies on it; the dicts in an `Overwrite` there are left as they are.
Lists and dicts the caller passed in are never changed: a write that
changes is replaced. So the id step can recognize the reducer without an
import cycle, `_messages_delta_reducer` now lives in
`langgraph.pregel._messages`; `langgraph.graph.message` re-exports it.

Visible changes: in a messages DeltaChannel, a node's update streams as
messages with ids, and a string is stored as a message (about 170 bytes
more each).

JS twin: langchain-ai/langgraphjs#2992. Thanks to @HarshShroff for
testing every `Overwrite` form and for the tuple fix.

## Tests

`test_delta_channel_id_stability.py` and
`test_delta_channel_update_state.py`: a write of every shape the reducer
accepts gets an id that every read keeps, as input, from a node and
through `update_state` (sync, async and as input); a list written twice
adds its messages twice and stays as it was; a forked `Command` gets an
id; a message dict the reducer rejects in a list still fails the run
before it's saved; a raw `Pregel` input gets an id on a new thread with
every durability, and its nodes see the ids that are saved; another
DeltaChannel keeps the dicts in an `Overwrite`. 36 of the 87 tests in
these files fail on main. The langgraph and prebuilt suites pass, and
lint is clean.

---------

Co-authored-by: Harsh Shroff <29751900+HarshShroff@users.noreply.github.com>
checkpoint==4.3.0
2026-10-12 20:33:45 +00:00
Elior Nataf LackritzandGitHub 395c145c04 fix(langgraph): save a cached node's writes like a node that ran (#9259)
A node served from the node cache had its writes applied but never
saved: the loop only streamed them. Plain channels didn't notice, since
the next checkpoint stores their value, but a `DeltaChannel` is rebuilt
from the saved writes, so its saved state lost the cached node's write
for good, under every durability. With `a -> b -> c` and `b` cached, a
second thread read back `log` as `a, c` next to `plain` as `a, b, c`.

The loop now saves a cache hit with `put_writes`, like a node that ran,
in all six places it matches cached writes. A new `cached` flag keeps
the hit streamed as cached and stops `put_writes` from writing it back
to the cache, which would also restart its TTL. A hit now costs the
saver write the node makes when it runs, and a cached `@task` call's
result is saved the same way.

The sync loop also stops caching a node that failed or was interrupted,
as the async loop already did: a cached error made the next run with the
same input skip the node without raising.

Found in review of langchain-ai/langgraphjs#2969. JS twin:
langchain-ai/langgraphjs#2980

## Tests

- `test_delta_channel_node_cache.py`: `b` runs on the first thread and
is a cache hit on the second, under every durability, with `invoke` and
`ainvoke`. Every checkpoint of the second thread reads the same in the
DeltaChannel and a plain channel, and the cache is written once. All 6
cases fail on main; without the `cached` check in `put_writes`, they
fail on the cache count.
- `test_a_node_that_fails_is_not_cached`, with `invoke` and `ainvoke`: a
cached node that raises raises again on the next thread. The sync case
fails on main.
- The two tests that spy on `PregelLoop.put_writes` pass the new keyword
through.
- `make format`, `make lint_package`, `make lint_tests`, and the
`langgraph`, `prebuilt` and `cli` suites pass (without Redis).
2026-10-12 14:24:38 -04:00
Igor SoarezandGitHub 10f1fabb3b fix(langgraph): stop at an interrupt_before breakpoint when a drain is requested before it (#9281)
When a drain is requested during the step right before an
interrupt_before breakpoint, the run stops with GraphDrained and the
breakpoint is lost: resuming the run skips it unintentionally.

The fix moves the drain check in tick() after the breakpoint check, so
breakpoints win over draining.

JS twin: langchain-ai/langgraphjs#3009
2026-10-12 18:29:56 +03:00
Elior Nataf LackritzandGitHub 799c2f04fd fix(langgraph): keep an exit run from a checkpoint the thread moved past out of its newer branch (#9269)
An exit-durability run that starts from a checkpoint the thread has
moved past, addressed by `checkpoint_id`, stores its DeltaChannel writes
on that checkpoint. The branch that already grew from it reads the
writes stored there, so its checkpoints picked up this run's writes too:

```python
graph.invoke({"log": ["in1"]}, config)  # nodes a and b add "a1", "b1"
turn_1 = graph.get_state(config).config
graph.invoke({"log": ["in2"]}, config)
turn_2 = graph.get_state(config).config
graph.invoke({"log": ["in3"]}, turn_1, durability="exit")
graph.get_state(turn_2).values["log"]
# ["in1", "a1", "b1", "in3", "a3", "b3", "in2", "a2", "b2"], was ["in1", "a1", "b1", "in2", "a2", "b2"]
```

Sync and async durability store each step's writes on the run's own
checkpoints, so they weren't affected. The run now snapshots the
DeltaChannels it wrote instead, as a run's input already does on a
checkpoint a `checkpoint_id` addressed (#9260). That costs one snapshot
of each channel the run wrote, even when the addressed checkpoint is the
latest one. Threads that already hit this keep the wrong values on the
existing branch.

Found by @hntrl in review of langchain-ai/langgraphjs#2974
([repro](https://gist.github.com/hntrl/2185e489abe22147b3f6f77010c18264)).
JS twin: langchain-ai/langgraphjs#2989

## Tests

`test_delta_channel_exit_mode.py`: one and two exit runs from the end of
turn 1, after turn 2, leave every checkpoint's DeltaChannel equal to a
plain reducer channel. Both fail on main on every saver in the fixture.
The `langgraph` suite passes (without Redis), and lint is clean.
2026-10-11 08:51:09 -04:00
Elior Nataf LackritzandGitHub b4991f1ba3 fix(langgraph): store an update_state input's writes on the checkpoint it updates (#9258)
`update_state(..., as_node="__input__")` stored its writes on the
checkpoint it saved. A DeltaChannel reads the writes stored on a
checkpoint's ancestors, not its own, so that checkpoint read back
without the input unless the channel snapshotted there, and once a later
checkpoint snapshotted, the input was gone for good. Only a raw `Pregel`
graph whose input channel is a DeltaChannel hits it, since a
`StateGraph`'s input goes to its start channel.

The input's writes now go on the checkpoint the update builds on, as a
node update's do. An update on a checkpoint the thread has moved past
stores nothing there and snapshots the DeltaChannels it writes on its
own checkpoint instead, the rule a node update already follows (#9165).

Both kinds of update now go through one helper, which also gives a
message an id before saving it, as the loop's `put_writes` does with
`ensure_message_ids`. Before, a message saved through `update_state`
without an id read back with id `None`, on the node path too, while the
same message from a node got one.

JS twin: langchain-ai/langgraphjs#2973, where review found it.

## Tests

`test_delta_channel_update_state.py`, sync and async: an update as input
reads back on its checkpoint and after the next run, with
`snapshot_frequency` 1 and 2, and an update as input to an older
checkpoint stays out of its other branch. The frequency 2 and
older-checkpoint cases fail on main. Five more check that a message
saved through `update_state` gets an id every read keeps, on the node
path (latest and older checkpoint) and the input path, sync and async;
they fail on main. The langgraph suite passes, and `lint_package` and
`lint_tests` are clean.
2026-10-10 11:57:46 +00:00
Elior Nataf LackritzandGitHub 6aa0afba68 fix(checkpoint): default InMemorySaver delta history to the latest checkpoint (#9257)
`InMemorySaver.get_delta_channel_history` looked its target up by
`config["configurable"].get("checkpoint_id", "")`, so a config without a
`checkpoint_id` matched no checkpoint, and every channel came back with
no seed and no writes, which a `DeltaChannel` reads as empty. The base
implementation, `PostgresSaver` and `SqliteSaver` read from the thread's
latest checkpoint instead, as `get_tuple` does.

A missing id now resolves to the namespace's newest checkpoint id, with
the same `max` that `InMemorySaver.get_tuple` uses. Graphs always pass a
checkpoint id here, so only direct callers of the saver API were
affected, and a call with an id does the same work as before.

Thanks @Hotragn, who pinned this down on #8242, where @longquanzheng's
branch had already fixed it.

JS twin: langchain-ai/langgraphjs#2979

## Tests

- `test_get_channel_writes_without_checkpoint_id_reads_the_latest` fails
on main (`{'messages': {'writes': []}}`).
- The `checkpoint`, `checkpoint-conformance`, `checkpoint-sqlite`,
`checkpoint-postgres` (Postgres 16), `prebuilt` and `langgraph` suites
pass, the last two without their Redis cases. The DeltaChannel
conformance suite also passes against `InMemorySaver`; CI skips that run
in `libs/checkpoint`, where the conformance package isn't installed, so
the new test lives in `test_memory.py`.
2026-10-10 00:59:20 +00:00
Elior Nataf LackritzandGitHub 12aeb0fddb fix(langgraph): read a run's DeltaChannel input back only on its own checkpoints (#9260)
A raw `Pregel` graph whose input channel is a DeltaChannel saved a run's
input to it as a `NULL_TASK_ID` write on the checkpoint the run started
from, under `"sync"` and `"async"` durability. Readers apply a
checkpoint's `NULL_TASK_ID` writes as its own state, so:

- on a new thread that checkpoint is never saved, and the first run's
input was lost for good: after `{"log": [0], "plain": [0], ...}`, `log`
read `[2]` next to `plain` `[0, 2]`;
- the last checkpoint of a run read the next run's input;
- a run with input from an older checkpoint (`checkpoint_id`) leaked its
input into the branch that already grew from it, and read that branch's
input when it had one.

The input's writes now go on the checkpoint the run starts from under a
task id of their own, `uuid5(checkpoint_id, INPUT)`, the one
`update_state` uses for an input update. On a new thread, or a
checkpoint a `checkpoint_id` addressed, which may already have children
that would read them, nothing is stored there and the input checkpoint
snapshots the channel instead. A normal run stores the same write as
before, and `durability="exit"`, which already kept the input right, is
unchanged. Threads saved before this keep the input writes already
stored on their checkpoints.

A `StateGraph` routes its input through its start channel, so only raw
`Pregel` graphs hit this.

JS twin: langchain-ai/langgraphjs#2981

## Tests

`test_delta_channel_run_input.py`, under every durability, with `invoke`
and `ainvoke`: two runs on a new thread, and a run with input from an
older checkpoint whose other branch had DeltaChannel input or none.
Every checkpoint reads the same in the DeltaChannel and a plain channel.
The 12 sync and async cases fail on main, and dropping the task id, the
new-thread snapshot or the addressed-checkpoint snapshot each fails its
own cases. The `langgraph` and `prebuilt` suites pass (without Redis),
and `lint_package` and `lint_tests` are clean.
2026-10-09 15:59:10 -04:00
Elior Nataf LackritzandGitHub d05236f805 fix(langgraph): snapshot a DeltaChannel that an update_state Overwrite resets (#9263)
A node that writes an `Overwrite` to a DeltaChannel makes the loop
snapshot the channel on the checkpoint that superstep saves, so no read
replays across the reset. The same write through `update_state`, as a
node or as input, didn't snapshot: the value read back right, but reads
of the update's checkpoint and the ones after it walked back past the
reset to the last snapshot. `update_state` now snapshots a DeltaChannel
an `Overwrite` resets, as the loop does.

Raised in review of langchain-ai/langgraphjs#2973. JS twin:
langchain-ai/langgraphjs#2982

## Tests

`test_delta_channel_update_overwrite.py`, sync and async: an `Overwrite`
through `update_state` as a node, and as input to a raw `Pregel` graph,
snapshots the channel on the checkpoint the update saves, and the value
reads back as the overwrite. All four fail on main. The `langgraph`
suite passes (without Redis), and `lint_package` and `lint_tests` are
clean.
2026-10-09 15:26:16 -04:00
Elior Nataf LackritzandGitHub 9d92f33cca fix(langgraph): keep a fork's DeltaChannel snapshot from starting nodes that never ran (#9264)
A fork from a checkpoint with pending writes to a DeltaChannel snapshots
the channel on the fork's first checkpoint, so the fork doesn't replay
the other branch's writes. If the channel had never been written there,
the snapshot also gives it its first version, and `_mark_bumps_seen`
only marked the bump seen for nodes that already have a `versions_seen`
entry. A node subscribed to the channel that never ran has none, so the
bump started it, and it read the empty value before the node that writes
the channel had run:

```python
graph.invoke("go", config)  # writer writes [1] to d, reader reads [1]
fork = graph.update_state(first_checkpoint, {"a": "go"}, as_node="__input__")
graph.get_state(fork).next  # ("writer", "reader"): resuming runs reader on [] first
```

A replay from that checkpoint saves the same kind of fork from the loop.
A channel bumped from no version was never written, so
`create_checkpoint` now also marks the bump seen for the nodes the
channel triggers, from the graph's `trigger_to_nodes`, at every call
that can bump. Only raw `Pregel` graphs hit this: `StateGraph` nodes
trigger on their `branch:to:*` channels, not on state keys. An
`as_node="__copy__"` fork still starts such a node, with a plain list
channel as well, so that case isn't DeltaChannel-specific and isn't
changed here.

Raised in review of langchain-ai/langgraphjs#2974. JS twin:
langchain-ai/langgraphjs#2983

## Tests

`test_delta_channel_seal_subscribers.py`: an update as input (sync and
async) and a replay from the checkpoint before a DeltaChannel's first
write leave only the writer next, and the reader then reads the written
value once. All three fail on main. The `langgraph` suite passes
(without Redis), and `lint_package` and `lint_tests` are clean.
2026-10-09 14:36:27 -04:00
Elior Nataf LackritzandGitHub 26356227c4 test(checkpoint): run the delta conformance suite against InMemorySaver in CI (#9261)
The conformance self-test in `libs/checkpoint-conformance` ran every
capability against `InMemorySaver` but asserted only the base ones.
`libs/checkpoint/tests/test_conformance_delta.py`, which ran the delta
conformance tests against it, always skips in CI: `libs/checkpoint`
can't depend on the conformance package, which depends on it. So no CI
job checked `InMemorySaver.get_delta_channel_history` against the delta
conformance tests.

The self-test now asserts every capability `InMemorySaver` implements,
and the skipped copy is gone.

## Tests

- With `InMemorySaver.get_delta_channel_history` broken to return no
history, the self-test now fails on 7 of the 10 delta conformance tests;
on main it still passes.
- `make format`, `make lint` and `make test` pass in
`libs/checkpoint-conformance`.
2026-10-09 13:44:55 -04:00
Elior Nataf LackritzandGitHub a5dbacae0d fix(checkpoint-postgres,checkpoint-sqlite): treat an empty checkpoint_id as the latest in delta history (#9262)
`PostgresSaver` and `SqliteSaver`, sync and async, read a DeltaChannel's
history from the latest checkpoint only when the config's
`checkpoint_id` was missing or `None`. An empty one was looked up as an
id, matched nothing, and came back with no seed and no writes, while
their own `get_tuple` treats an empty id as the latest checkpoint, as
the default implementation does. They now check for a missing or empty
id the way `get_tuple` does. The in-memory saver gets the same in #9257.

Graphs always pass the id of a saved checkpoint, so only direct callers
of the saver API hit this.

## Tests

-
`test_{sync,async}_empty_checkpoint_id_reads_from_the_latest_checkpoint`
in `checkpoint-postgres/tests/test_delta_pagination.py` and
`checkpoint-sqlite/tests/test_delta_parent_walk.py`: all four fail on
main.
- The `checkpoint-postgres` (Postgres 16) and `checkpoint-sqlite` suites
pass, and `lint_package` and `lint_tests` are clean in both.
2026-10-09 13:44:51 -04:00
cba111d8d6 fix(langgraph): don't save a checkpoint past a failed DeltaChannel write (#9235)
A DeltaChannel is rebuilt from its writes along the parent chain, so a
checkpoint saved without one of them reads back short for good. If
saving a DeltaChannel write failed (a database blip, say), the next
checkpoints were saved anyway and the channel lost that write, while
plain channels kept it. Three things let that happen:

- the sync loop waited for the delta writes before saving a checkpoint,
but never checked that they succeeded;
- both loops saved a checkpoint even when the previous save had failed,
so it pointed at a parent that was never saved;
- each save took the pending write list only when it started in the
background, and saves can start out of order, so a save could take a
later checkpoint's writes and not wait for its own. Waiting on writes
queued behind it, a save could also hang a sync run with
`durability="async"` (the default) once every worker was such a save: on
a 15-core machine a loop of 100 fast steps hung every time with default
settings, and with `max_concurrency=1` three steps are enough.

Now `_put_checkpoint` hands each save the writes submitted before it,
and a save fails if one of them or the previous save failed. The run
raises the write's error as before, the thread stays at its last
checkpoint that has all its writes, and running it again reruns the
task. For graphs without a DeltaChannel, a failed save now also stops
the later saves of that run, as JS already does, instead of saving
checkpoints whose parent is missing.

Thanks @shivangsharma01 for reproducing this in #8234, and @iroiro147,
whose #8299 had the first two changes before the issue-assignment check
closed it. Thanks also to @HarshShroff for the failed-save test case.

JS twin: langchain-ai/langgraphjs#2969

## Tests

`test_delta_channel_write_failures.py`:

- a saver fails one delta write once; on every durability, with `invoke`
and `ainvoke`, every saved checkpoint matches a plain channel and a
retry gets the write back. The `invoke` cases and `ainvoke` with
`durability="async"` fail on main.
- a saver fails the save of the checkpoint after `a` once; with `invoke`
and `ainvoke`, every saved checkpoint matches a plain channel and a
retry finishes the run. The `durability="async"` cases fail on main,
which saves the later checkpoints on top of the missing one.
- a delta graph run with `max_concurrency=1` finishes. It hangs on main.

Reverting any one of the three changes fails at least one of these.
`make format`, `make lint` and the langgraph suite pass. A 100-step
benchmark (delta and plain channels, every durability, with and without
1 ms of saver latency) makes the same saver calls and runs in the same
time as main, except for the case that hangs on main.

---------

Co-authored-by: iroiro147 <265728356+iroiro147@users.noreply.github.com>
2026-10-09 12:48:24 +00:00
Elior Nataf LackritzandGitHub 93a5a28008 perf(checkpoint-postgres): start the delta walk at the target (#9248)
Reading a DeltaChannel at an older checkpoint (the state at a past
checkpoint, each entry of `get_state_history`, a fork or replay from
one) walked `checkpoints` down from the newest row, so every newer row
was read before the target's chain. A checkpoint's ancestors have
smaller ids, the order `get_tuple` already relies on to find the latest
checkpoint, so the walk now starts at the target: the first page is
`checkpoint_id <= target`, later pages stay `< cursor`.

The cursor is never NULL anymore, so the `(cursor IS NULL OR
checkpoint_id < cursor)` predicate goes too. Once Postgres caches a
generic plan for the prepared statement (`from_conn_string` sets
`prepare_threshold=0`), that predicate is a filter rather than an index
condition, and each later page re-read every newer row.

`get_delta_channel_history` on a 6,000-checkpoint thread with a snapshot
every 200 checkpoints, median of three runs of 60 reads each, same
results before and after:

| target | main | this PR |
|---|---|---|
| newest | 3.1 ms | 2.7 ms |
| 1,000 back | 4.5 ms | 2.9 ms |
| 3,000 back | 8.9 ms | 2.8 ms |
| 5,000 back | 15.7 ms | 2.8 ms |

The target is now always the first row read, so the pagination tests
from #8556 can no longer leave it off the first page; they are renamed
for what they still cover, a walk that continues across pages.

## Test plan
- [x] `test_{sync,async}_walk_reads_nothing_newer_than_the_target`
record the rows the walk reads; both fail on main, which also reads the
three newer checkpoints.
- [x] `checkpoint-postgres` suite on Postgres 16: 281 passed, 3 skipped.
- [x] `langgraph` DeltaChannel tests against this saver (`-k "delta and
not redis"`): 1,154 passed, 1 skipped.
2026-10-09 08:31:15 -04:00
Baihao WangGitHubBaihao Wangopen-swe[bot] <open-swe@users.noreply.github.com>
bfcfea554e fix(checkpoint,checkpoint-postgres,checkpoint-sqlite): validate namespace labels before store dispatch (#9217)
The SQLite and Postgres stores save a namespace as its labels joined
with `.`, so a label containing `.` could resolve to a different
namespace: `("foo.bar",)` and `("foo", "bar")` share the same row. This
rejects those labels at every entry point.

- `BaseStore` and `AsyncBatchedBaseStore`: `get`, `search`, `delete`,
and `list_namespaces` (sync and async) reject labels that are empty, not
strings, or contain `.`. The check runs before an op is queued, so one
caller's bad label can't fail other callers' concurrent requests.
- New `langgraph.store.base.validate_op_namespace(op)` applies the same
label checks to a single op. `SqliteStore`/`AsyncSqliteStore` and
`PostgresStore`/`AsyncPostgresStore` call it from `_group_ops` before
any SQL runs, which covers direct `batch`/`abatch` calls. Other stores
that serialize namespaces as delimited text can call it too.
- Unchanged: hierarchical prefix search, empty-prefix `search(())`, `*`
wildcards in `list_namespaces`, and the existing `put` rules.

## Release note

`get`, `search`, `delete`, and `list_namespaces` now raise
`InvalidNamespaceError` for labels that are empty, not strings, or
contain `.`, where they previously returned `None` or `[]` (or, on the
SQLite and Postgres stores, matched a different namespace). `put`
already rejected these labels, so nothing written through `put` becomes
unreachable.

## Release order

Release `langgraph-checkpoint` first. `langgraph-checkpoint-sqlite` and
`langgraph-checkpoint-postgres` import `validate_op_namespace`, so they
need the `langgraph-checkpoint` release that ships it. `main` already
has `libs/checkpoint` at 4.3.0 and requires
`langgraph-checkpoint>=4.3.0` in both stores (from #8544), so this must
merge before 4.3.0 is released; if 4.3.0 ships first, bump to the next
version and raise both requirements to it. That also guarantees the
pre-queue checks are installed: with an older `langgraph-checkpoint`, an
invalid op would fail inside the shared `abatch` and reject the calls
batched with it.

---------

Co-authored-by: Baihao Wang <byhow@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-10-08 16:10:55 -07:00
Elior Nataf LackritzandGitHub 93f5eaff21 fix(checkpoint): keep serialized data when an object can't be rebuilt (#9251)
Fixes #6970

If a checkpointed object can't be rebuilt on load (its module was
removed or renamed, or its constructor now rejects the stored fields),
`JsonPlusSerializer` returned `None` for it, so the value silently
disappeared from restored state. The constructor and method ext codes
now return the serialized payload instead, the same thing the pydantic
and blocked-type paths already do, and log a one-time warning per type.
The warning names the exception type only, since exception messages can
echo the stored value.

Thanks @yangbaechu for the report and repro. This takes the same
direction as #6972 by @pandego and #7152 by @SinzoL.
2026-10-08 16:01:46 -04:00
Baihao WangandGitHub 5965d72ff7 fix(langgraph,prebuilt): stop ToolNode from swallowing invalid resume values (#9232)
**Problem.** `interrupt(response_schema=...)` checks a human's answer
when the graph resumes. If the answer doesn't match the schema, the
resume fails, nothing is saved, and the human can answer again (#8886).
That works when the interrupt runs in a graph node, but not when it runs
inside a tool: either the tool calls `interrupt()` itself, or it starts
a graph that does, such as a subagent called as a tool. There, the
resume returns normally and the interrupt disappears.

**Why.** `interrupt()` raises a `pydantic.ValidationError` for an
invalid answer. When one comes out of a tool, `ToolNode` assumes the
model passed bad arguments, so it hands the error to the model ("Error
invoking tool … Please fix the error and try again") and the run carries
on. The human never sees the error, the model is blamed for it, and the
interrupt is no longer pending.

**Fix.** `interrupt()` still raises the same `ValidationError`, but
marks it so a new helper, `langgraph.errors.is_invalid_resume(error)`,
can recognize it. `ToolNode` re-raises these errors instead of handing
them to the model, whatever `handle_tool_errors` is set to, so a bad
answer fails the resume the same way inside a tool as outside one:
nothing is saved and the interrupt can be answered again. Every other
`ValidationError` from a tool is handled as before.

**Also fixed, in the same error handling.** With `wrap_tool_call` set
and a `handle_tool_errors` other than the default (for example `True`),
`ToolNode` turned any exception from the wrapper into an error
`ToolMessage`, including `GraphInterrupt`. So an interrupt in that setup
never paused: the model got `Error: GraphInterrupt(...)` instead.
Interrupts now propagate there too, as they already do without a
wrapper. `create_agent` uses the default handler, so it was not
affected.

**Compatibility.** Not a breaking change: the error type is unchanged.
Worth a careful look: a wrapped `ToolNode` with a non-default
`handle_tool_errors` now pauses on interrupts instead of returning them
to the model as errors. With an older `langgraph` that doesn't have
`is_invalid_resume`, `ToolNode` keeps today's behavior.
2026-10-08 12:59:25 -07:00
Elior Nataf LackritzandGitHub 40a2e6d845 fix(langgraph): never store exit-mode delta writes under the null task id (#9229)
In exit mode, a run stores its DeltaChannel writes on the checkpoint it
started from, under synthetic task ids that put the superstep first. For
a `Command`'s writes in a run whose first superstep is 0, that id came
out as `NULL_TASK_ID` itself. Readers take writes under `NULL_TASK_ID`
for the checkpoint's own pending writes, so after
`invoke(Command(update=...), durability="exit")`:

- on a new thread, `get_state` on the empty first checkpoint showed the
update in the DeltaChannel but not in a plain channel;
- on a thread whose first checkpoint came from `update_state(...,
as_node="__input__")`, `get_state` on that checkpoint showed the update
the same way, and a replay or fork from it applied the update to the
DeltaChannel only.

`exit_delta_task_id` now never returns `NULL_TASK_ID`. Threads already
saved this way stay as they are.

## Tests

- `test_command_update_on_an_input_checkpoint_matches_a_plain_channel`
compares every checkpoint in the history, and a replay from the input
checkpoint, with a plain channel, on every checkpointer and durability.
The exit cases fail without the fix.
- `test_exit_command_update_on_a_new_thread_matches_a_plain_channel`
compares every checkpoint in a new thread's history with a plain
channel, on every checkpointer, and fails without the fix. It runs in
exit mode only: in sync and async the two channels already differ on
`main`, because of a separate bug that applies a new thread's `Command`
update twice.

`make format`, `make lint` and the langgraph suite pass.
2026-10-07 19:17:02 -04:00
Elior Nataf LackritzandGitHub a0053bb616 fix(sdk-py): end a thread stream's run only on a root lifecycle event (#9228)
The thread stream's lifecycle watcher ended the run on any `completed`
or `failed` lifecycle event, including the one a subgraph sends when it
finishes. So `thread.output` could read the thread state before the
parent stored the step that ran the subgraph, and a run that failed
after a subgraph completed was reported as completed. The async and sync
watchers now end the run only on a root event, with the
`_is_root_terminal_lifecycle` check the fanout already uses. The JS SDK
checks the root namespace here too.

This is the `sdk-py integration` flake where the final `items` comes
back as `['streamed', 'tool', 'asked']` without `'sub'`: the example
graph's last node runs a subgraph.

## Tests

New async and sync tests send a subgraph `completed` and then a root
`failed`. Without the fix the run ends as completed. `make lint` and
`make test` in `libs/sdk-py` pass.
2026-10-07 19:03:46 -04:00
Igor SoarezandGitHub 87f1c8eb9a fix(langgraph): stop astream_events dropping control/interrupts on v1/v2 (#9219)
### Problem

`Pregel.astream_events` declared `interrupt_before`, `interrupt_after`
and
`control` as keyword-only parameters, but forwarded them only on the
`version="v3"` branch. On async `version="v1"`/`"v2"` the values were
bound to
named parameters and never entered `**kwargs`, so they were silently
dropped
on the way to `astream` — no error, no effect:

- `request_drain()` on a caller-supplied `RunControl` did nothing; the
graph
  created its own control and ran to completion.
- Static interrupts passed as `astream_events(...,
interrupt_before=[...])`
  never fired.

This is a regression introduced by #7677 (first released in `1.2.0a3`).
Before that, `Pregel` did not override `astream_events`, and these
keywords
reached `astream` through `**kwargs` — langchain-core's v1 and v2 event
implementations both forward caller kwargs to `astream`
(`tracers/log_stream.py`, `tracers/event_stream.py`).

Downstream impact: langgraph-api passes run-level `interrupt_before` /
`interrupt_after` into `graph.astream_events(..., version="v2",
**kwargs)` for
runs with `stream_mode="events"` (`models/run.py`, `stream.py`), so
server
runs using that stream mode have silently dropped static interrupts
since
langgraph 1.2.0a3.

Sync `stream_events(version="v1"/"v2")` is unaffected: langchain-core
raises
`NotImplementedError` there, so there was no working sync path to break.

### Fix

Remove the three parameters from the public runtime implementations of
`stream_events` / `astream_events` (and from the explicit passing in
their v3
dispatch calls), so the values travel through `**kwargs` again:

- **v1/v2** recover the pre-#7677 passthrough. `astream` receives
exactly what
the caller passed — a supplied value, an explicit `None`, or nothing for
an
  omitted argument.
- **v3** is unchanged. The values bind on `_pregel_stream_v3` /
`_apregel_stream_v3`, which keep their named parameters and
since-inception
(#7519, `1.2.0a1`) explicit-`None` defaults: an omitted argument arrives
at
  `astream` as `None`, exactly as before.

What `astream` receives after this change:

| caller supplies | async v1/v2 | v3 (sync and async) |
|---|---|---|
| nothing | argument absent | explicit `None` |
| explicit `None` | `None` | `None` |
| a value | the value | the value |

The typed `version="v3"` `@overload` stubs are untouched, so v3 call
sites
keep their static types (invalid values still fail `ty` there, same as
on
`main`). `RemoteGraph` and the v3-only `transformers` parameter are
untouched.

Complexity: net −24 lines in `main.py` with no branches, sentinels or
wrappers added. The public capture-and-drop pattern that caused the bug
is
gone; the two private helpers each have a single call path and forward
unconditionally, so they cannot drop anything.

Docstrings now describe the three parameters as honored on every async
version (type-checked only on the v3 overloads), and no longer promise
synchronous v1/v2 event streaming, which langchain-core does not
implement.

### Compatibility notes

- The three parameters were keyword-only, so no caller can break;
keyword
  callers bind through `**kwargs` identically.
- The names leave the runtime signatures (`inspect.signature`), while
the v3
  overloads keep the typing.
- v3 is unchanged: `_pregel_stream_v3`/`_apregel_stream_v3` still
default all
  three to `None` and pass them explicitly, so an override's non-`None`
default never applied on v3 and still doesn't. The only behavior change
beyond restoring the pre-#7677 passthrough is on v1/v2 with an explicit
  `None`: since 1.2.0a3 the named-parameter capture dropped it, so an
  override's non-`None` default was silently applied instead; now the
explicit `None` reaches `astream`, as it did before 1.2.0 and as it does
on
  v3.

### Testing

New tests in `tests/test_stream_events_v3_kwarg_forwarding.py`:

- `interrupt_before` / `interrupt_after` / pre-drained `control`
parametrized
  over v1/v2/v3 (12 of them fail on unpatched `main`).
- Sync v3 static interrupts.
- Mid-run drain: a node calls `request_drain()`; asserts `GraphDrained`
  propagates, the caller's own `RunControl` was used, and the checkpoint
  keeps the pending step.
- Recording tests pin, for all three names and on both the async and
sync v3
paths, exactly what `(a)stream` receives: supplied values (with
`control`
  identity), explicit `None`, and absence for omitted arguments.

Verified by mutation: replacing the implementation with each rejected
alternative (unpatched parent; injecting `None` for omitted kwargs on
v1/v2;
dropping explicit `None` on v1/v2; kwargs-only private helpers) makes
the
corresponding tests fail.

Suites: 246 passed on the four adjacent streaming test files; 906 passed
/
1 skipped across every test file calling `(a)stream_events` plus
`test_runtime.py`. `ruff check` / `format --check` clean; `ty check
langgraph`
clean.

Not verifiable locally (CI please): Python 3.10 (the new tests carry no
version skip), minimum supported langchain-core, and a live
langgraph-api
server run.

### Release note

> Fixed a regression since 1.2.0a3: `Pregel.astream_events` silently
dropped
> `interrupt_before`, `interrupt_after` and `control` for
> `version="v1"`/`"v2"`. Static interrupts and `RunControl` drains now
work on
> every async version. Server runs using `stream_mode="events"` were
affected
> and get their static interrupts back.
2026-10-07 12:26:50 -04:00
gethin-langchainandGitHub 736a18eaab release(cli): 0.4.33 (#9227)
Bumping the CLI to 0.4.33 to cut a release including #9221 (deploy
listeners list) and #9222 (--image-uri).
cli==0.4.33
2026-10-07 09:19:34 -04:00
gethin-langchainandGitHub ec4f8535f8 feat(cli): add --image-uri to deploy an already-pushed image (#9222)
## Summary

`--push-to` always builds (or retags a local `--image`) and pushes, even
when the image already exists at the destination. That breaks CI/CD
pipelines where the build/push step and the deploy step run in separate
jobs: the deploy job has no local copy of the image to retag, and
`--image` requires one (it runs `docker image inspect`, which needs the
image present in the local Docker daemon).

This adds `--image-uri`, which takes a full image reference already in a
registry and deploys it directly via `source_revision_config.image_uri`,
with no local Docker involvement at all: no inspect, no build, no tag,
no push. It gets the same placement behavior as `--push-to`
(`--listener-id`/`--k8s-namespace`, or auto-selecting the sole listener)
and the same update-in-place semantics, since both produce an
`external_docker` deployment and are interchangeable on the same
deployment.

`--image-uri` requires a digest (`repo@sha256:...`) and rejects
empty/blank input. `--push-to` always resolves to a digest after
pushing; `--image-uri` has no push step to resolve one from, so a
mutable tag (or an unvalidated empty string) could let Kubernetes
silently keep running a previously cached image while the CLI reports
success.

Implementation: `CustomerRegistrySource`'s image-acquisition step is
split into two variants, `BuildAndPush` (the existing
`--push-to`/`--image` flow, unchanged behavior) and `PublishedImage`
(the new flag), so create/update/placement logic stays shared. Also
reworded `_ensure_customer_registry_source`'s error, which previously
mentioned only `--push-to` even though it's reachable from `--image-uri`
too.

## Test plan

- [x] `make format && make lint` clean in `libs/cli`
- [x] Unit tests in `test_deploy_helpers.py` for `_select_source`
selecting `PublishedImage` (by digest, trimmed), requiring no local
Docker, carrying placement, and the mutual-exclusivity + validation
errors (`--push-to`, `--image`, `--tag`, `--remote`, empty/blank input,
missing digest)
- [x] CLI-level tests in `test_deploy_command.py`: create and update an
external deployment via `--image-uri` with zero Docker calls, listener
auto-placement, rejecting a non-external existing deployment (now
mentioning both flags), and the conflicting-flag cases end to end
- [x] Full `libs/cli` suite: 524 passed, no regressions
2026-10-07 13:32:46 +01:00
gethin-langchainandGitHub ce14d33687 feat(cli): add 'langgraph deploy listeners list' (#9221)
## Summary

Originally this auto-selected a workspace's sole listener for
self-hosted/hybrid control planes the same way #9056 already does for
Cloud. Per review, that's reverted: in self-hosted environments, leaving
placement blank is the deliberate signal to deploy to the bundled
operator, not an unresolved default. Auto-selecting a sole listener
there would silently take that option away from anyone who has both a
bundled operator and one listener configured, with no way to get it
back.

The actual need behind this was simpler: a way to find a listener's id
without hardcoding it, so it can be passed to `--listener-id`
explicitly. `HostBackendClient.list_listeners()` already existed and is
used internally for placement resolution, but had no CLI surface of its
own.

This adds `langgraph deploy listeners list`, mirroring the existing
`deploy list` / `deploy revisions list` pattern, to look up a
workspace's listeners and their namespaces. No change to default
placement behavior.

## Test plan

- [x] `make format && make lint` clean in `libs/cli`
- [x] `format_listeners_table` unit test in `test_util.py`
- [x] CLI-level tests for `deploy listeners list` (with and without
results) in `test_cli.py`
- [x] Full `libs/cli` suite: 508 passed, no regressions
2026-10-07 13:32:26 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
708aaa4ebc chore(deps): bump notebook from 7.5.7 to 7.6.3 in /libs/langgraph (#9206)
Bumps [notebook](https://github.com/jupyter/notebook) from 7.5.7 to
7.6.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jupyter/notebook/releases">notebook's
releases</a>.</em></p>
<blockquote>
<h2>v7.6.3</h2>
<h2>7.6.3</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.2...9c8d7c24006554dda8c5fc02c69f91d6449c712a">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Update to JupyterLab v4.6.4 <a
href="https://redirect.github.com/jupyter/notebook/pull/8066">#8066</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-08-11&amp;to=2026-09-21&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/jtpio"><code>@​jtpio</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-08-11..2026-09-21&amp;type=Issues">activity</a>)</p>
<h2>v7.6.2</h2>
<h2>7.6.2</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.1...2f1f1622fc64e09b90ade87ed886fdfe1bc653fb">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Add nvd.nist.gov to the check_links ignore list <a
href="https://redirect.github.com/jupyter/notebook/pull/8032">#8032</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Backport JupyterLab dependency updater improvements <a
href="https://redirect.github.com/jupyter/notebook/pull/8031">#8031</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Update to JupyterLab v4.6.3 <a
href="https://redirect.github.com/jupyter/notebook/pull/8030">#8030</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Switch local pre-commit hooks to language: system <a
href="https://redirect.github.com/jupyter/notebook/pull/8002">#8002</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<h3>Documentation improvements</h3>
<ul>
<li>Update 'notebook v7 proposal' link in doc <a
href="https://redirect.github.com/jupyter/notebook/pull/8004">#8004</a>
(<a href="https://github.com/brichet"><code>@​brichet</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-07-22&amp;to=2026-08-11&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/brichet"><code>@​brichet</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Abrichet+updated%3A2026-07-22..2026-08-11&amp;type=Issues">activity</a>)
| <a href="https://github.com/jtpio"><code>@​jtpio</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-07-22..2026-08-11&amp;type=Issues">activity</a>)</p>
<h2>v7.6.1</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jupyter/notebook/blob/@jupyter-notebook/tree@7.6.3/CHANGELOG.md">notebook's
changelog</a>.</em></p>
<blockquote>
<h2>7.6.3</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.2...9c8d7c24006554dda8c5fc02c69f91d6449c712a">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Update to JupyterLab v4.6.4 <a
href="https://redirect.github.com/jupyter/notebook/pull/8066">#8066</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-08-11&amp;to=2026-09-21&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/jtpio"><code>@​jtpio</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-08-11..2026-09-21&amp;type=Issues">activity</a>)</p>
<!-- raw HTML omitted -->
<h2>7.6.2</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.1...2f1f1622fc64e09b90ade87ed886fdfe1bc653fb">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Add nvd.nist.gov to the check_links ignore list <a
href="https://redirect.github.com/jupyter/notebook/pull/8032">#8032</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Backport JupyterLab dependency updater improvements <a
href="https://redirect.github.com/jupyter/notebook/pull/8031">#8031</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Update to JupyterLab v4.6.3 <a
href="https://redirect.github.com/jupyter/notebook/pull/8030">#8030</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Switch local pre-commit hooks to language: system <a
href="https://redirect.github.com/jupyter/notebook/pull/8002">#8002</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<h3>Documentation improvements</h3>
<ul>
<li>Update 'notebook v7 proposal' link in doc <a
href="https://redirect.github.com/jupyter/notebook/pull/8004">#8004</a>
(<a href="https://github.com/brichet"><code>@​brichet</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-07-22&amp;to=2026-08-11&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/brichet"><code>@​brichet</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Abrichet+updated%3A2026-07-22..2026-08-11&amp;type=Issues">activity</a>)
| <a href="https://github.com/jtpio"><code>@​jtpio</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-07-22..2026-08-11&amp;type=Issues">activity</a>)</p>
<h2>7.6.1</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.0...72c228d76d1a9e5aa81531f7cf3c6af410c5e53f">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Update to JupyterLab v4.6.2 <a
href="https://redirect.github.com/jupyter/notebook/pull/7996">#7996</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jupyter/notebook/commit/dc710245bf156f11bafc6e7d283695253d6b5cd7"><code>dc71024</code></a>
Publish 7.6.3</li>
<li><a
href="https://github.com/jupyter/notebook/commit/9c8d7c24006554dda8c5fc02c69f91d6449c712a"><code>9c8d7c2</code></a>
Update to JupyterLab v4.6.4 (<a
href="https://redirect.github.com/jupyter/notebook/issues/8066">#8066</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/ffc52152951a52ef4885f12521d7a5f8ebd2f9c1"><code>ffc5215</code></a>
Publish 7.6.2</li>
<li><a
href="https://github.com/jupyter/notebook/commit/2f1f1622fc64e09b90ade87ed886fdfe1bc653fb"><code>2f1f162</code></a>
Update to JupyterLab v4.6.3 (<a
href="https://redirect.github.com/jupyter/notebook/issues/8030">#8030</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/63df75281ec7226826877f2e77dc68670b109c33"><code>63df752</code></a>
Backport JupyterLab dependency updater improvements (<a
href="https://redirect.github.com/jupyter/notebook/issues/8031">#8031</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/66101117b79c92baf364d95647242f490807f18c"><code>6610111</code></a>
Backport PR <a
href="https://redirect.github.com/jupyter/notebook/issues/8032">#8032</a>:
Add nvd.nist.gov to the check_links ignore list (<a
href="https://redirect.github.com/jupyter/notebook/issues/8033">#8033</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/75a02cb28e7ed7a58358b69323be3d9e4800f941"><code>75a02cb</code></a>
Backport PR <a
href="https://redirect.github.com/jupyter/notebook/issues/8004">#8004</a>:
Update 'notebook v7 proposal' link in doc (<a
href="https://redirect.github.com/jupyter/notebook/issues/8005">#8005</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/2b0ebe6584d3f6d59d458a9414f00c985ead4feb"><code>2b0ebe6</code></a>
Backport PR <a
href="https://redirect.github.com/jupyter/notebook/issues/8002">#8002</a>:
Switch local pre-commit hooks to language: system (<a
href="https://redirect.github.com/jupyter/notebook/issues/8003">#8003</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/e058ab3a0d98a4698f201e10d7de723c70150d34"><code>e058ab3</code></a>
Publish 7.6.1</li>
<li><a
href="https://github.com/jupyter/notebook/commit/72c228d76d1a9e5aa81531f7cf3c6af410c5e53f"><code>72c228d</code></a>
Update to JupyterLab v4.6.2 (<a
href="https://redirect.github.com/jupyter/notebook/issues/7996">#7996</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/tree@7.5.7...@jupyter-notebook/tree@7.6.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=notebook&package-manager=uv&previous-version=7.5.7&new-version=7.6.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/langchain-ai/langgraph/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-07 17:21:37 +09:00
Elior Nataf LackritzandGitHub 39c523eb0a fix(langgraph): give each bulk_update_state update its own task id (#9128)
`bulk_update_state` stores each update's writes on the checkpoint it
updates, under a task id. An update whose node has no pending task to
reuse got `uuid5(checkpoint_id, INTERRUPT)`, so every such update in one
superstep shared an id. Savers keep one write per `(task_id, idx)`, so
all but the first update's writes were dropped.

Plain channels don't notice, since their value is stored in the new
checkpoint. A `DeltaChannel` rebuilds its value from those writes, so it
lost every update after the first, on memory, sqlite and postgres:

```python
graph.bulk_update_state(config, [[
    StateUpdate({"d": ["u1"], "p": ["u1"]}, as_node="a"),
    StateUpdate({"d": ["u2"], "p": ["u2"]}, as_node="m"),
]])
# plain: [..., 'u1', 'u2']
# delta: [..., 'u1']
```

The existing multi-update test only passed because it gave each update
an explicit `task_id`, and its docstring said so.

## Fix

The `i`th update gets `uuid5(checkpoint_id, f"{INTERRUPT}:{i}")`. The
first keeps the old id, so a single `update_state` stores exactly what
it did before. Updates that reuse a pending task's id, or pass their
own, are unchanged.

Each update also gets the task path `(__interrupt__, i)`, stored with
its writes. Live execution applies a superstep's updates in the order
given, and a saver that replays a checkpoint's writes by task path
(#8544) now gives them back in that order instead of by task id. Savers
whose `put_writes` takes no `task_path` get the old call.

## Limits

- On savers that order a checkpoint's writes by task id only (the
released ones, until #8544), several updates in one superstep still
replay in task id order.
- langgraphjs has the same shared id in `bulkUpdateState` and loses the
same update; fixed in langchain-ai/langgraphjs#2923 with the same ids.

## Tests

`test_delta_channel_update_state.py` adds sync, async and
next-to-a-pending-task cases across the checkpointer fixtures, with no
explicit task ids, on a thread that already has history (a fresh thread
snapshots every delta channel and hides the bug). All 19 fail on main.
Two more (sync and async) give six updates in one superstep and check
that `get_state` returns them in that order, on a saver that replays by
task path; they fail without the path.
2026-10-07 01:04:58 +00:00
3a1796ecf0 fix(langgraph): replay a resumed exit-mode run's delta writes in live order (#9114)
Depends on #8544

Resuming an exit-durability run after a parallel interrupt replays the
resumed checkpoint's `DeltaChannel` writes wrong: twice on `main`, out
of order if the duplicate is simply dropped. `p` finished before `q`
interrupted, and `r` runs after `q`:

```
live:            ['in1', 'p', 'r']
main, reload:    ['in1', 'p', 'r', 'p']
```

No fork is involved. Any exit-mode run that starts from a checkpoint
with pending delta writes hits it: resuming an interrupt, or retrying
after a task error.

## Cause

Exit durability stores a run's delta writes on the checkpoint it started
from, under step-prefixed task ids (`exit_delta_task_id`), so they
replay in superstep order. On a resume, that checkpoint already holds
the finished tasks' writes under their real task ids. The accumulator
stored those loaded writes again under a step-prefixed id, so they
replayed twice. Skipping them alone reorders the replay, because the
real ids sort after the step-prefixed ones.

## Fix

At exit:

- writes loaded with the checkpoint are skipped, since they are already
stored on it: `NULL_TASK_ID` writes by task id (this run's own `Command`
writes are recorded separately in `_first`), the rest by `(task_id,
channel)`;
- the checkpoint's own superstep keeps its real task paths, so it
interleaves with the loaded writes as live execution did, but gets a
step-prefixed task id. Under the real id, a resume whose final
checkpoint fails to save would leave the resumed task looking done, and
the retry would skip it and lose its other writes;
- a resume addressed by `checkpoint_id` reruns tasks whose writes are
already stored on the checkpoint; their writes to those channels are
skipped, and a write to a channel the task did not write before is kept;
- later supersteps get task id `ffffffff-<step>-...` and task path
`~~<step>...`, which sort after every real task id and every real task
path, in step order.

So superstep order holds whether a saver orders by task path (#8544) or
only by task id.

## Limits

- Within the resumed superstep, a saver that orders only by task id
replays this run's writes before the ones loaded from the checkpoint.
#8544 fixes that for the OSS savers.
- If the final checkpoint fails to save, the writes of supersteps after
the resumed one stay on the checkpoint and replay once more after the
retry (on `main`, every write does). That comes from exit durability
storing its writes before its checkpoint, not from this change.

## Tests

`test_delta_channel_exit_mode.py`, on the shared checkpointer fixture
(memory, sqlite, postgres) in all three durabilities:

- resume after a parallel interrupt with a later write, plain and with
the head's `checkpoint_id`
- the resumed superstep interleaved by task path: `a_asks` resumes after
`z_done` finished, and live order puts `a` first
- the same runs on a saver that orders writes by task id only
- a resume retried after its final checkpoint failed to save
- a resume with `Command(resume=..., update=...)` that writes the delta
channel replays that write once, in live order
- an addressed resume whose rerun task writes a delta channel it did not
write before keeps that write

The exit cases fail without the change, except the last one, which
guards against skipping by task id alone (an earlier version of this PR
did); sync and async pass either way.

#8548 marked exit durability in
`test_resume_on_an_interrupted_head_consumes_its_writes_without_a_snapshot`
as a strict expected failure for this bug; this PR drops the mark.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: ErenAta16 <149434812+ErenAta16@users.noreply.github.com>
Co-authored-by: ragnarok268 <58264829+ragnarok268@users.noreply.github.com>
2026-10-06 22:05:55 +00:00
2b93e8b79f fix: order delta channel replay by task path (#8544)
Fixes langchain-ai/langgraph#8382

`DeltaChannel` rebuilds its value by replaying ancestor writes through
the reducer. Every saver ordered a checkpoint's writes by `(task_id,
idx)`, but live execution applies a super-step's writes in task-path
order (`apply_writes` sorts tasks by `task_path_str(task.path[:3])`).
`task_id` is a hash of the path, so when two or more tasks write one
`DeltaChannel` in the same super-step, replay applies them in an
arbitrary permutation.

Reducers must be batching-invariant, not order-invariant, so the
permutation changes the value: `get_state` disagrees with what `invoke`
returned, and continuing the thread saves the reordered value as the
base for every later write.

## Fix

Replay orders by `(task_path, task_id, idx)`, the order
`SELECT_PENDING_SENDS_SQL` already uses for sends. `apply_writes` and
every saver now sort with one `writes_sort_key` from
`langgraph.checkpoint.base`, in Python, so live and replay can't drift
apart and don't depend on a database collation. `apply_writes` sorts by
the full task path, the string `put_writes` stores, instead of
`path[:3]`. The paths that reach `apply_writes` no longer carry task
ids, so the live order doesn't change.

`BaseCheckpointSaver`'s default `get_delta_channel_history` can't sort
by path, since `PendingWrite` has no task path, so it replays each
checkpoint's writes in `get_tuple` order. `get_tuple` now has to return
`pending_writes` in `writes_sort_key` order, and memory, SQLite and
Postgres do, so the default walk is right for any saver that follows
that. `AsyncPostgresSaver` also gets the sync
`get_delta_channel_history` that `AsyncSqliteSaver` already had; sync
reads used to fall back to the default walk.

Memory and Postgres already stored `task_path`. SQLite accepted it on
`put_writes` and dropped it, so `writes` gains the column and `setup()`
adds it to existing databases.

Writes without a task path (graph input, `update_state` updates, rows
written before the column existed) sort first by `task_id`, which is
also where live execution applies input.

## Compatibility

- Memory and Postgres already had `task_path` on disk, so existing
threads replay in the corrected order after upgrade.
- On SQLite, rows from before the upgrade read back as `''` and keep
their old order. Only new writes get the corrected order, since there is
no stored path to recover.
- SQLite has no `ADD COLUMN IF NOT EXISTS`, so `setup()` runs the
`ALTER` and treats `duplicate column name` as success, which also covers
two processes migrating one file. That error comes while SQLite prepares
the statement, before it asks for the write lock, so `setup()` on an
up-to-date database doesn't wait on other writers. A read-only database
from before the column is read with empty paths instead of failing
setup.
- Downgrade is safe: older code's `INSERT` omits the column and the
column has a default.
- `get_tuple` and `list` return `pending_writes` in `writes_sort_key`
order instead of task id order (SQLite, Postgres) or put order (memory).
Nothing in langgraph depends on the old order.
- Postgres reads `task_path` and `idx` with each pending write, so a
subclass that pairs `SELECT_SQL` with its own `_load_writes`, or the
other way round, has to match the new row shape.
- A third-party saver has to replay in `writes_sort_key` order: in its
own `get_delta_channel_history` if it has one, otherwise by returning
`pending_writes` from `get_tuple` in that order. Otherwise it fails the
new conformance tests; the `get_tuple` one is a base test, so it runs
for every saver.
- langgraph, checkpoint-sqlite and checkpoint-postgres import
`writes_sort_key` from langgraph-checkpoint, so this bumps
langgraph-checkpoint to 4.3.0 and requires it there. 4.3.0 has to be
released first.

## Limits

- Several updates in one `bulk_update_state` super-step share a task id,
so the saver keeps only the first one's writes and the `DeltaChannel`
loses the rest (plain channels are fine). That's on main too; #9128
fixes it and stores a task path per update, so with this PR those
updates also replay in the order given.
- Exit durability stores its writes differently; resume ordering there
is fixed in #9114, stacked on this PR.
- langgraphjs applies `DeltaChannel` writes in task id order, live and
on replay (langchain-ai/langgraphjs#2544), so its reads match too.
Moving JS to task path order is a follow-up.

## Tests

Each fails on main and passes here:

- `test_delta_channel_parallel_order.py`, across memory, SQLite and
Postgres: parallel writers and a `Send` fan-out, comparing `get_state`
with the live result, including sync `get_state` on the async savers.
- Three conformance tests whose task ids sort opposite to their task
paths, so they cannot pass by chance: two on
`get_delta_channel_history`, one on `get_tuple`'s `pending_writes`
order.
- SQLite migration tests from a pre-column database, sync and async,
including a read-only file.

One more that passes on main too: SQLite `setup()` while another
connection holds the write lock, with no busy timeout, sync and async.
It keeps the `ALTER` from waiting on that lock.

Thanks to @ErenAta16 for the report, the reproduction, and for tracing
`task_path` through all three backends, and to @ragnarok268 for the
conformance-test design with task ids ordered opposite to their paths.

---------

Co-authored-by: ErenAta16 <149434812+ErenAta16@users.noreply.github.com>
Co-authored-by: ragnarok268 <58264829+ragnarok268@users.noreply.github.com>
2026-10-06 17:55:04 -04:00
Nick HollonandGitHub 70dd64065b release(langgraph): 1.2.14 (#9215)
Bumps langgraph from 1.2.13 to 1.2.14.

Raises the minimum `langgraph-sdk` to 0.4.6, which percent-encodes
`thread_id` and `assistant_id` in thread stream requests (#9213). Remote
graph streaming uses those thread stream classes, so this keeps it on a
version with the fix.

Also includes:

- Keep DeltaChannel counters on every `update_state` path (#9142)
- Keep an `update_state` on an older checkpoint out of its other
branches (#9165)
- Fork before replaying an update checkpoint the thread moved past
(#9170)
1.2.14
2026-10-06 10:35:44 -04:00
Nick HollonandGitHub 55b0e36c51 release(sdk-py): 0.4.6 (#9214)
Bumps the Python SDK version from 0.4.5 to 0.4.6. Percent-encodes
`thread_id` and `assistant_id` in thread stream requests (#9213).
sdk==0.4.6
2026-10-06 10:15:20 -04:00
Nick HollonandGitHub d89c7e100e fix(sdk-py): percent-encode thread_id and assistant_id in thread stream requests (#9213)
## Summary

Two REST helpers on the thread stream built their paths by interpolating
the raw identifier:

- `thread.agent.get_tree()` built `/assistants/{assistant_id}/graph`
- the state fetch behind `thread.output` built
`/threads/{thread_id}/state`

httpx collapses `..` segments and treats `#` as a fragment, so an
identifier containing those characters was rewritten into a different
path before the request was sent. Both now go through
`_quote_path_param` in the async and sync stream modules, matching the
other SDK endpoints and the stream transports.

## Tests

`tests/streaming/test_thread_stream_path_encoding.py` drives
`threads.stream(...)` followed by `thread.output` or
`thread.agent.get_tree()`, async and sync, with identifiers containing
`..`, `/`, and `#`. It asserts that the request path keeps each
identifier as a single encoded segment. All four tests fail without the
change.

`make format`, `make lint`, and `make test` pass in `libs/sdk-py`.
2026-10-06 09:57:28 -04:00
Elior Nataf LackritzandGitHub 2d942085e2 fix(langgraph): fork before replaying an update checkpoint the thread moved past (#9170)
Depends on #9165

A replay saves a fork checkpoint first, so its writes land on the fork. Two things still reached the checkpoint it replayed from, and through it every branch that already grew from that checkpoint.

It skips the fork for an update or fork checkpoint, which is already a branch of its own. Once the thread has moved past such a checkpoint it can have children, and the replay's writes stored on it reach every one of them. Edit a checkpoint, continue from it, then replay the edit, and the branch you continued reads back a write it never ran:

```
plain channel: ['in1', 'a', 'b', 'edit', 'in2', 'a', 'b']
DeltaChannel:  ['in1', 'a', 'b', 'edit', 'b', 'in2', 'a', 'b']
                                         ^ the replay's b
```

And a `Command(update=...)` or `Command(goto=...)` replayed from any checkpoint stored its writes there before the run saved its fork. The branches that grew from that checkpoint replayed the update into a `DeltaChannel`, and a later replay of the same checkpoint repeated the old `Command`: the update again, in every channel, or the `goto`'s node again.

Both happen on `main`.

## Fix

Loading a checkpoint addressed by `checkpoint_id` checks, for update and fork checkpoints only, whether the thread has moved past it, with #9165's `checkpoint_superseded`. If it has, the replay saves its fork checkpoint as it does from any other checkpoint. Subgraphs keep replaying from the edit's parent, as they did without the fork.

The run decides on the fork before it stores anything. When it forks, it keeps the `Command`'s writes in memory and applies them, and the fork snapshots the delta channels they write, so the fork carries them and nothing lands on the checkpoint the run addressed.

Cost: one extra `get_tuple` when a run addresses an update or fork checkpoint by `checkpoint_id`, such as resuming with the config `update_state` returned. A replay from an edit the thread moved past stores one more checkpoint, and a forked `Command` that writes a delta channel stores a snapshot of it.

## Limits

- A `Command(resume=...)` addressed at a checkpoint the thread moved past doesn't fork, so its run's writes still land there, and a branch that grew from that checkpoint without answering the interrupt replays them. Same on `main`. A fork would give the tasks new ids, and interrupt ids and resume-map keys are hashes of the task's namespace, which includes the task id, so a resume map built from the interrupts the caller just read would stop matching. This needs writes that record their branch (#9174).

## Tests

`test_delta_channel_fork.py`, on the shared checkpointer fixtures in all durabilities:

- replay from an edit the thread moved past, with and without a subgraph, sync and async, with no input and with `Command(update=...)`
- a `Command(update=...)` or `Command(goto=...)` replay of a plain checkpoint the thread moved past: the branch that grew from it reads back unchanged, and a later replay of the checkpoint doesn't repeat the `Command`

124 of the 186 cases fail on #9165; the exit ones pass either way.
1.2.13
2026-10-05 13:46:44 -04:00
456e2b1acc fix(langgraph): keep an update_state on an older checkpoint out of its other branches (#9165)
Fixes #8551

`update_state` stores its writes on the checkpoint it addresses. A
`DeltaChannel` rebuilds its value by replaying the writes stored on its
ancestors, so when that checkpoint already has another child, the edit
shows up in that branch too. #8551's repro, editing an earlier turn and
then reading the branch that already existed:

```
before the edit: ['in-1', 'first-out', 'in-2', 'second-out']
after the edit:  ['in-1', 'first-out', 'patched', 'in-2', 'second-out']
```

The plain reducer channel in the same graph is unaffected. #8548 already
keeps the edited branch itself correct; this is the other direction.

## Fix

When `update_state` addresses a checkpoint that is not the thread's
latest, the checkpoint it creates snapshots the delta channels the
update writes, through the same snapshot #8548 adds for forks, and none
of the update's writes are stored on the addressed checkpoint, whatever
channels it writes. The edited branch reads the snapshot, and the other
branches have nothing new to replay. The addressed checkpoint stays as
it was, so a later `as_node=END` update on it doesn't take the edit in,
and the edit doesn't show as that checkpoint's task result. On `main`
both can happen in any graph, with or without a `DeltaChannel`, and a
`DeltaChannel` also takes in the other branch's writes.

"Not the latest" is one extra `get_tuple` for the thread, made when the
config names a `checkpoint_id`. It compares with the latest put, so a
checkpoint that has a child always counts. So does a leaf of an
abandoned branch, such as the old head after a fork elsewhere, where
nothing could leak; telling the two apart would mean listing the thread,
since savers have no lookup by parent. The addressed checkpoint's
pending writes can't answer it either: a finished turn that a later run
continued from has none, which is #8551's case.

Updates on the latest checkpoint are unchanged: no snapshot, same
writes.

## Cost

Editing an older checkpoint stores one snapshot per delta channel the
update writes, the size of that channel's regular snapshot. That
includes editing a leaf of an abandoned branch, as above.

## Limits

- Threads that already leaked keep the leaked write, since it is stored
on the old checkpoint.
- The second report in #8551, `RemoveMessage(id=REMOVE_ALL_MESSAGES)`
through `_messages_delta_reducer`, is that reducer's documented limit
and isn't changed here.

## Tests

`test_delta_channel_fork.py`, on the shared checkpointer fixtures:

- `update_state` / `aupdate_state` on an older checkpoint, both a
finished turn and one whose next node already ran there: the other
branch reads back unchanged, and continuing it stays clean
- `bulk_update_state` with two supersteps from an older checkpoint
- `update_state` with the head's `checkpoint_id` still stores no
snapshot
- `update_state(None, as_node=END)` on an edited checkpoint: an older
one leaves the edit out, also when it wrote only plain channels, and the
latest one keeps it in both channels

33 of the 59 cases fail on `main`. The rest pass either way: the head
case, the case whose next node already ran, where the saver keeps that
node's own write and drops the edit's, and `as_node=END` on the latest
checkpoint.

Thanks to @AnnaSuSu for the report, the repro, tracing the leak to the
writes landing on the addressed checkpoint, and the note that the fix
needs a snapshot on the new checkpoint first.

---------

Co-authored-by: Wenchao An <64579968+AnnaSuSu@users.noreply.github.com>
2026-10-05 17:40:47 +00:00
Elior Nataf LackritzandGitHub 1b84cb0873 fix(langgraph): keep DeltaChannel counters on every update_state path (#9142)
`update_state` saves `counters_since_delta_snapshot` on the checkpoint
it creates, except on three paths: `update_state(None, as_node=END)`,
`as_node="__input__"` and `as_node="__copy__"`. Those save their
checkpoint without it, so the next checkpoint restarts every delta
channel's counters from zero:

```
before update_state(None, END): [6, 9]
after it:                       (none)
after the next run:             [2, 3]   (with this change: [6, 10], then [8, 13])
```

The counters decide when a channel snapshots, so after any of these
updates the next snapshot comes later than `snapshot_frequency` and
reads walk further back. A thread driven only by these updates never
snapshots, so its walk keeps growing. The field's docstring says it is
absent only on threads that don't use delta channels.

## Fix

`END` and `__input__` build their checkpoint with
`create_checkpoint_plan_for_update_state_api`, the plan an update as a
node already uses, which now takes the checkpoint's `source`. The
counters advance by one superstep (`END` counts the channels its
absorbed writes touched as updated), and a channel that reaches its
bound snapshots right there. `__copy__` saves a checkpoint with the same
values on the same parent, so it keeps the copied checkpoint's counters.

## Tests

`test_delta_channel_supersteps_bound.py`, sync and async:
- each of the three paths saves the base's counters advanced by one
superstep (or unchanged for `__copy__`).
- `END` and `__input__` snapshot a channel that reaches its supersteps
bound.

All 10 fail on main.
2026-10-05 13:04:30 -04:00
Igor SoarezandGitHub 8e15e0d0bc release(langgraph): 1.2.13 (#9205)
Bumps langgraph from 1.2.12 to 1.2.13.

Stops reporting answered interrupts in `get_state()` (#9103, fixes
#6956,
fixes #8579): latest-state reads now omit interrupts from finished
tasks,
and `Command(resume=value)` without an interrupt id raises when more
than one
interrupt is pending.

Also fixes DeltaChannel history handling: subgraph delta channels now
hydrate with the caller-resolved saver (#8538), an abandoned branch is
no
longer replayed into a DeltaChannel fork (#8548), and history is no
longer
walked for a DeltaChannel that was never written (#9141).

Dependency updates in `libs/langgraph`: pyjwt 2.13.0 → 2.15.1,
urllib3 2.7.0 → 2.8.0, tornado 6.5.8 → 6.5.9, notebook 7.5.6 → 7.5.7.
2026-10-05 12:13:11 -04:00
Elior Nataf LackritzandGitHub 524b320e30 fix(langgraph): don't walk history for a DeltaChannel that was never written (#9141)
A `DeltaChannel` with no version at a checkpoint was never written, so
its value is empty. `channels_from_checkpoint` still asked the saver for
its history, and with no snapshot to stop at, the walk reads every
ancestor of the thread, on every run and every `get_state`. A channel
that never gets written is common: deepagents' `files` channel when an
agent doesn't use files.

On SQLite the walk fails outright once the thread is long enough,
because stage 2 binds one variable per ancestor. With one never-written
channel on a 33,000-step thread:

```
main:   get_state  -> OperationalError: too many SQL variables
        next run   -> OperationalError: too many SQL variables
branch: get_state ok in 1 ms, next run ok
```

## Fix

Only channels that have a version at the checkpoint are walked. A
channel without one hydrates empty without asking the saver.

A version is assigned whenever a channel is written (by a task, an
input, `update_state` or a migration from a plain channel), so no
version means no write on this branch. The walk could only have found
writes this branch never applied.

Snapshotting such a channel instead would also bound the walk, but it
writes a blob for an empty value on every thread. Today
`create_checkpoint` skips any channel without a version, so even the
forced `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` snapshot never lands for
it, and the walk has no bound.

## Tests

`test_delta_channel_supersteps_bound.py`: a graph whose second delta
channel is never written asks the saver only for the written channel's
history, sync and async. Both fail on main (`asked for [['a', 'b'],
['a', 'b']]`). A third test covers the case the skip must not break: a
delta channel's first write, left pending on an interrupted head before
the channel has a version, lands exactly once on resume. It passes on
main too.

JS twin: langchain-ai/langgraphjs#2927.
2026-10-05 11:20:32 -04:00
9a0394d88b fix(langgraph): don't replay an abandoned branch into a DeltaChannel fork (#8548)
Fixes #8443
Fixes #9089

A checkpoint keeps the pending writes that produced its child, and
nothing records which child consumed them. When a new branch starts from
a checkpoint that already has pending writes (going back in time, or new
input on an interrupted head), the `DeltaChannel` ancestor walk replays
those writes into the new branch too. The live run is correct; only a
reload is wrong:

```
fork base:     ['in-1', 'first-out']
fork returns:  ['in-1', 'first-out', 'in-3', 'third-out']
reload gives:  ['in-1', 'first-out', 'in-2', 'in-3', 'third-out']
                                     ^^^^^^ from the branch the fork replaced
```

Plain channels store their full value and are unaffected, so the tests
use one as the oracle.

## Fix

The first checkpoint of a new branch snapshots the delta channels its
base has pending writes for, so the walk stops inside the branch. Only
the base's own writes are branch-specific; everything above it is shared
history. A base with no pending writes has nothing to leak, so an
ordinary turn that addresses the head (as clients commonly do) stores
nothing. `bulk_update_state` takes the set from its first superstep
only: a `__copy__` is stored under the base's parent, so nothing after
it walks the base's writes. A resume that is not replaying reuses the
head's pending writes instead of rerunning their tasks, so it seals only
the loaded writes that don't go back to their task: a finished task
whose `Send` a `Command(goto=...)` replaced, or an error handler that
runs again. A plain resume stores nothing. A resume addressed by
`checkpoint_id` reruns them, so it still seals.

`put` only stores a blob for a channel whose version moved since the
last stored checkpoint, so a snapshot of one that didn't move needs a
version bump, and scheduling reads versions. `create_checkpoint`
therefore advances every `versions_seen` entry that had seen the old
version, including the interrupt tracker. Without the advance, the bump
re-fires `interrupt_before` on resume and reruns the channel's
subscribers. For each entry it advances, `SNAPSHOT_BUMPS` keeps the
version the node really read, so `update_state`'s `as_node` inference
reads `versions_seen` as if the bump never happened. A never-written
channel gets a version only for the seal; the cadence and a fresh
thread's first `update_state` skip it.

`update_state` no longer records its narrower `updated_channels` when it
snapshots; it skipped a deferred node listed in `next` on resume
(#9089).

The same seal fixes two `update_state` calls on one checkpoint (editing
the same message twice): both store their writes there under the same
task id, the saver keeps the first, and the second branch read back the
first one's edit.

Two things this touches were also wrong on `main`: a resumed error
handler that runs again left its stored writes on the head (an exit
reload read them twice), and `aupdate_state` on a thread seeded only by
updates raised "Ambiguous update" where `update_state` applied the
update as the input. `update_state` and `aupdate_state` now share one
`as_node` inference.

Exit durability has a separate replay bug on `main` when a resumed
checkpoint already holds writes (duplicated or reordered replay),
unrelated to forks. It's fixed in #9114; the resume test here marks exit
durability as a strict expected failure until then.

`tests/memory_assert.py` now compares against the checkpoint as read
back: a delta channel a step didn't write is refilled on read, which the
old comparison reported as a mutation.

Cost: 300 turns addressing the head store no snapshots, as on `main`. A
resume that reruns finished tasks seals every time. After a parallel
task finished, 30 turns of resuming with the head's `checkpoint_id`
(what Studio sends) stored 30 snapshots, 191 KB, against 12 KB of delta
writes, and a subgraph resume with a finished sibling does the same,
since a subgraph loop always counts as replaying. That seal is what
keeps a rerun task's new write from being replayed as its old one:
without it, a subgraph task that returns something different on the
rerun reads back its first result. The reruns happen on `main` too, and
stopping them would remove this cost.

276 of 464 cases in `test_delta_channel_fork.py` fail on `main` and pass
here (memory, sqlite and postgres, all durabilities). #9089's own case
is in `test_delta_channel_update_state.py`, the cadence case in
`test_delta_channel_supersteps_bound.py`, and the `as_node` cases in
`test_pregel.py`.

## Limits

- Threads forked before this change keep their state: the ownership was
never recorded, so there is nothing to recover.
- With exit durability, a fork at a finished turn stores its writes on
the shared base, so the original branch then replays them too (`['h1',
'ai', 'h2-edited', 'ai', 'h2', 'ai']`). Same on `main`.
- `Command(update=..., goto=...)` sent to an old checkpoint stores the
update there, so the original branch replays it too. The fork itself is
correct now; the original branch is the same as on `main`.
- #8551 (the mirror case: `update_state`'s own writes leaking into the
abandoned branch) is fixed in #9165, stacked on this PR. It builds on
this snapshot, but keys off whether the addressed checkpoint is the
thread's latest rather than on pending writes, which a finished turn
that a later run continued from doesn't have.

Thanks to @AnnaSuSu for the report, the reproduction and the snapshot
approach, and to @UditDewan for the implementation in #8476. Both are
co-authors.

---------

Co-authored-by: AnnaSuSu <64579968+AnnaSuSu@users.noreply.github.com>
Co-authored-by: UditDewan <194863456+UditDewan@users.noreply.github.com>
2026-10-03 08:55:59 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7dc9195e41 chore(deps): bump notebook from 7.5.6 to 7.5.7 in /libs/langgraph (#9168)
Bumps [notebook](https://github.com/jupyter/notebook) from 7.5.6 to
7.5.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jupyter/notebook/releases">notebook's
releases</a>.</em></p>
<blockquote>
<h2>v7.5.7</h2>
<h2>7.5.7</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.5.6...af55f111d335315edd9e5eab472c9c1bbbb17b27">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Pin Node to 22.x in UI tests <a
href="https://redirect.github.com/jupyter/notebook/pull/7940">#7940</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Update to JupyterLab v4.5.8 <a
href="https://redirect.github.com/jupyter/notebook/pull/7939">#7939</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-04-30&amp;to=2026-06-04&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/jtpio"><code>@​jtpio</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-04-30..2026-06-04&amp;type=Issues">activity</a>)</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jupyter/notebook/blob/@jupyter-notebook/tree@7.5.7/CHANGELOG.md">notebook's
changelog</a>.</em></p>
<blockquote>
<h2>7.5.7</h2>
<p>(<a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.5.6...af55f111d335315edd9e5eab472c9c1bbbb17b27">Full
Changelog</a>)</p>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Pin Node to 22.x in UI tests <a
href="https://redirect.github.com/jupyter/notebook/pull/7940">#7940</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
<li>Update to JupyterLab v4.5.8 <a
href="https://redirect.github.com/jupyter/notebook/pull/7939">#7939</a>
(<a href="https://github.com/jtpio"><code>@​jtpio</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-04-30&amp;to=2026-06-04&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/jtpio"><code>@​jtpio</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-04-30..2026-06-04&amp;type=Issues">activity</a>)</p>
<!-- raw HTML omitted -->
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jupyter/notebook/commit/a25fa5eda09ef85984ddafe4a5def427bf34912b"><code>a25fa5e</code></a>
Publish 7.5.7</li>
<li><a
href="https://github.com/jupyter/notebook/commit/af55f111d335315edd9e5eab472c9c1bbbb17b27"><code>af55f11</code></a>
Update to JupyterLab v4.5.8 (<a
href="https://redirect.github.com/jupyter/notebook/issues/7939">#7939</a>)</li>
<li><a
href="https://github.com/jupyter/notebook/commit/1f7059106ebdd038ecd30512295e2d1f77b7d698"><code>1f70591</code></a>
Pin Node to 22.x in UI tests to avoid Playwright install hang (<a
href="https://redirect.github.com/jupyter/notebook/issues/7940">#7940</a>)</li>
<li>See full diff in <a
href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/tree@7.5.6...@jupyter-notebook/tree@7.5.7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=notebook&package-manager=uv&previous-version=7.5.6&new-version=7.5.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/langchain-ai/langgraph/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 14:14:46 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1fd716c44a chore(deps): bump virtualenv from 21.7.12 to 21.7.13 in /libs/cli (#9167)
Bumps [virtualenv](https://github.com/pypa/virtualenv) from 21.7.12 to
21.7.13.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/virtualenv/releases">virtualenv's
releases</a>.</em></p>
<blockquote>
<h2>21.7.13</h2>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<ul>
<li>👷 ci: correct a stale checkout pin comment by <a
href="https://github.com/gaborbernat"><code>@​gaborbernat</code></a> in
<a
href="https://redirect.github.com/pypa/virtualenv/pull/3254">pypa/virtualenv#3254</a></li>
<li>🔧 chore: drop misc as a changelog fragment type by <a
href="https://github.com/gaborbernat"><code>@​gaborbernat</code></a> in
<a
href="https://redirect.github.com/pypa/virtualenv/pull/3255">pypa/virtualenv#3255</a></li>
<li>👷 ci: scope the nushell apt key to its own repo by <a
href="https://github.com/gaborbernat"><code>@​gaborbernat</code></a> in
<a
href="https://redirect.github.com/pypa/virtualenv/pull/3253">pypa/virtualenv#3253</a></li>
<li>🐛 fix(activation): stop path command injection in bash and fish by
<a href="https://github.com/gaborbernat"><code>@​gaborbernat</code></a>
in <a
href="https://redirect.github.com/pypa/virtualenv/pull/3252">pypa/virtualenv#3252</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/pypa/virtualenv/compare/21.7.12...21.7.13">https://github.com/pypa/virtualenv/compare/21.7.12...21.7.13</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst">virtualenv's
changelog</a>.</em></p>
<blockquote>
<h1>Bugfixes - 21.7.13</h1>
<ul>
<li>Fix <code>activate</code> and <code>activate.fish</code> running
commands embedded in the virtual environment path or in the
interpreter's Tcl/Tk library paths. (:issue:<code>3252</code>)</li>
</ul>
<hr />
<p>v21.7.12 (2026-09-18)</p>
<hr />
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pypa/virtualenv/commit/0c295ff1a5f298e8e11935e3588f59f7455c1f8f"><code>0c295ff</code></a>
release 21.7.13</li>
<li><a
href="https://github.com/pypa/virtualenv/commit/4d5a105ec2a2723b8c7f4571bb68f4f71d01e3f6"><code>4d5a105</code></a>
🐛 fix(activation): stop path command injection in bash and fish (<a
href="https://redirect.github.com/pypa/virtualenv/issues/3252">#3252</a>)</li>
<li><a
href="https://github.com/pypa/virtualenv/commit/0525dcea21865059ffedc70054f6f982be723992"><code>0525dce</code></a>
👷 ci: scope the nushell apt key to its own repo (<a
href="https://redirect.github.com/pypa/virtualenv/issues/3253">#3253</a>)</li>
<li><a
href="https://github.com/pypa/virtualenv/commit/aa8323a907834e9c16fb734613ce41a6d7e27260"><code>aa8323a</code></a>
🔧 chore: drop misc as a changelog fragment type (<a
href="https://redirect.github.com/pypa/virtualenv/issues/3255">#3255</a>)</li>
<li><a
href="https://github.com/pypa/virtualenv/commit/a43547765e017f3a13f029e24c6e6f73882e15bc"><code>a435477</code></a>
👷 ci: correct a stale checkout pin comment (<a
href="https://redirect.github.com/pypa/virtualenv/issues/3254">#3254</a>)</li>
<li>See full diff in <a
href="https://github.com/pypa/virtualenv/compare/21.7.12...21.7.13">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=virtualenv&package-manager=uv&previous-version=21.7.12&new-version=21.7.13)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/langchain-ai/langgraph/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-02 14:14:30 -07:00
3af263175f fix(langgraph): hydrate subgraph delta channels with the caller-resolved saver (#8538)
Fixes langchain-ai/langgraph#8470
Fixes langchain-ai/langgraph#8653

Reported by @gururafiki, with a self-contained `InMemorySaver` repro and
the observation that non-delta channels in the same namespace hydrate
fine, which is what makes the failure silent. @doniyor2109 reported
#8653, the same missing saver at the root: a graph compiled without a
checkpointer, whose saver arrives through the config, read the channel
back empty in `get_state`, `get_state_history` and `update_state`.

### The bug, in one read

One subgraph state, two channels written by the same nodes: `delta` is a
`DeltaChannel`, `plain` is an `operator.add` list. Pause the subgraph
before its second node and read it through the documented
`get_state(config, subgraphs=True).tasks[0].state`:

```
main:   {'delta': [],     'plain': ['a1']}
branch: {'delta': ['a1'], 'plain': ['a1']}
```

Same call, same instant, same state object. If this were a rule about
how subgraphs manage state, both channels would be empty. Only the delta
one is, because it is the one channel type that stores nothing in
`channel_values` and has to replay its writes through a saver.

### Why only the delta channel

A subgraph has no saver of its own. It either inherits the parent's (the
default, "per-invocation") or opts in with `checkpointer=True`
("per-thread"), and in both cases the saver reaches it through
`CONFIG_KEY_CHECKPOINTER`. All four public readers resolve it from
there. `_prepare_state_snapshot` then ignored that and re-derived the
saver from `self.checkpointer`:

- per-invocation: `self.checkpointer` is `None`
- per-thread: `self.checkpointer` is `True`, and `isinstance(True,
BaseCheckpointSaver)` is `False`

So the explicit per-thread opt-in, the mode that exists to make subgraph
state readable across invocations, was broken too. With no saver the
ancestor walk never runs and the channel falls through to
`from_checkpoint(MISSING)`: an empty value, indistinguishable from never
written, raising nothing.

The saver can't be recovered inside the function: `get_state_history`
passes the checkpointer's stored config, which never carries a live
saver. The caller is the only place it exists, so the caller passes it,
as a required keyword argument.

### What stays unchanged

The two modes from the [subgraph persistence
docs](https://docs.langchain.com/oss/python/langgraph/use-subgraphs#subgraph-persistence)
where an empty read is correct are pinned by tests that pass before and
after:

- `checkpointer=False` persists nothing, so there is no subgraph
namespace to read.
- after a subgraph completes, `subgraphs=True` has no pending task to
attach state to, for every channel type alike.

### The write path loses data on disk

`bulk_update_state` / `abulk_update_state` carried the same expression.
When an update reaches the channel's snapshot cadence,
`create_checkpoint` persists a `_DeltaSnapshot` built from the empty
hydration, so `update_state` on a subgraph namespace replaces `['a1',
'b1', 'b2']` with `['manual']` permanently. At the default
`snapshot_frequency=1000` no snapshot is written and the loss stays
latent; the tests use `snapshot_frequency=2` to reach it.

`prepare_next_tasks` in `_prepare_state_snapshot` now receives the same
saver too. It was inert there (the task config falls back to
`CONFIG_KEY_CHECKPOINTER`, and `PregelTask` exposes no config), but one
expression is easier to trust than two.

### One saver lookup and namespace rule

The run loop and all six state methods now share one saver lookup
(`_resolve_checkpointer`) and one namespace rule for `checkpointer=True`
subgraphs, and the state methods find the subgraph a namespaced config
addresses through one helper (`_subgraph_for_namespace`). Before, only
`get_state` / `aget_state` stripped the task id, so `get_state_history`
and `update_state` given the subgraph task's config looked under
`name:<task_id>`, where the run never stores anything: the history came
back empty and the update was silently lost.

The namespace rule strips only the task ids: a task that calls the same
`checkpointer=True` subgraph twice stores the second call under
`<node>|1`, and `recast_checkpoint_ns` would drop that counter.

Sharing the lookup with runs also fixes two places where a state method
disagreed with a run: a `checkpointer=False` graph ignores a saver lent
through the config, so `update_state` raises "No checkpointer set"
instead of writing a checkpoint no run reads, and a `checkpointer=True`
graph used as root raises the run's `checkpointer=True cannot be used
for root graphs.` instead of an AttributeError.

`channels_from_checkpoint` now raises when a `DeltaChannel` has a
version but no stored value and no saver or config was passed, so a
caller that forgets either fails instead of reading `[]`. Keying on the
version keeps a never-written channel reading as empty.

### Verification

`tests/test_delta_channel_subgraph.py` runs against the shared
`sync_checkpointer` / `async_checkpointer` fixtures (memory, sqlite,
postgres), and every assertion compares both channels:

| surface | on main |
| -- | -- |
| `get_state` / `aget_state` on a subgraph ns | `delta: []` |
| `get_state_history` / `aget_state_history` | every snapshot `delta:
[]` |
| two levels of nesting | `delta: []` |
| `get_state(subgraphs=True)` / async, interrupted, per-invocation and
per-thread | `delta: []` |
| `update_state` / `aupdate_state` | `delta: ['manual']`, prior history
lost |
| `get_state_history` / `update_state` from a `checkpointer=True`
subgraph's task config, sync and async | no snapshots / update lost |
| `channels_from_checkpoint` with a written delta channel and no saver
or config | silent `[]` |
| `get_state` / `update_state` / `get_state_history` on a graph compiled
without a checkpointer, saver lent through the config (#8653), sync and
async | `delta: []` |
| `get_state` of a `checkpointer=True` subgraph's second call in one
task (`node\|1`), sync and async | the first call's state |

159 cases: 144 fail on main, all 159 pass here. The 15 that pass on main
are the two unchanged-mode controls and the never-written case.

---------

Co-authored-by: gururafiki <22777967+gururafiki@users.noreply.github.com>
Co-authored-by: Yuan Gao <119447586+DavidGao520@users.noreply.github.com>
2026-10-02 15:26:54 +00:00
Igor SoarezandGitHub e6cf9ea667 fix(langgraph): stop reporting answered interrupts in get_state (#9103)
Execution, snapshots, and resume checks interpreted the same pending
writes separately.

When one of several interrupted tasks finished after resuming,
`get_state()` still reported its answered question as pending.

Use `read_task_statuses()` across execution, state reads, and resume
checks.
An output write marks a task finished; `RESUME` alone does not, since
the
task may pause again. Record `NO_WRITES` when a resumed task completes
without output, so it isn't run again.

Latest-state reads now omit interrupts from finished tasks. History and
explicit checkpoint reads still show the last recorded interrupt per
task. A task paused at its second interrupt appears in `next` with
`result=None`. `Command(resume=value)` without an id now raises when
more than one interrupt is pending, including in a subgraph.

Threads paused before this change, where a resumed task finished without
output, still show that task as unfinished. It appears in `next` and its
answered interrupt counts as pending, so if another interrupt is also
pending, `Command(resume=value)` without an id raises. Resume these
threads by interrupt id. On SQLite and Postgres, insert-ignore can leave
an old `RESUME` value for a finished task; that task does not run again.

Fixes #6956
Fixes #8579

Thanks to @gautamvarmadatla and @russeell for reporting these.
2026-10-02 11:02:27 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>John Kennedyopen-swe[bot] <open-swe@users.noreply.github.com>
157a06dda9 chore(deps-dev): bump the minor-and-patch group across 1 directory with 5 updates (#9155)
Bumps the minor-and-patch group with 5 updates in the /libs/langgraph
directory:

| Package | From | To |
| --- | --- | --- |
| [langchain-core](https://github.com/langchain-ai/langchain) | `1.6.1`
| `1.6.5` |
| [pytest-mock](https://github.com/pytest-dev/pytest-mock) | `3.15.1` |
`3.16.0` |
| [syrupy](https://github.com/syrupy-project/syrupy) | `6.0.0` | `6.1.1`
|
| [ruff](https://github.com/astral-sh/ruff) | `0.16.5` | `0.16.9` |
| [ty](https://github.com/astral-sh/ty) | `0.0.75` | `0.0.84` |


Updates `langchain-core` from 1.6.1 to 1.6.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langchain/releases">langchain-core's
releases</a>.</em></p>
<blockquote>
<h2>langchain-core==1.6.5</h2>
<p>Changes since langchain-core==1.6.4</p>
<p>release(core): 1.6.5 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40816">#40816</a>)
fix(core): abbreviate long tool IDs in XML buffer strings (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40792">#40792</a>)</p>
<h2>langchain-core==1.6.4</h2>
<p>Changes since langchain-core==1.6.3</p>
<p>release(core): 1.6.4 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40718">#40718</a>)
chore(core): deprecate chat message history (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40711">#40711</a>)
chore(deps): bump anyio from 4.12.0 to 4.14.2 in /libs/core (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40634">#40634</a>)
chore(deps): bump soupsieve from 2.8.4 to 2.9 in /libs/core (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40574">#40574</a>)</p>
<h2>langchain-core==1.6.3</h2>
<p>Changes since langchain-core==1.6.2</p>
<p>release(core): 1.6.3 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40407">#40407</a>)
feat(core): Allow model name and provider tracing metadata override
based on gateway response (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40406">#40406</a>)
test(core): cover the deprecated <code>.text()</code> access path (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40243">#40243</a>)
docs(core): remove stale Args/Raises entries from
FileCallbackHandler._write and ChatGeneration.set_text (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40211">#40211</a>)</p>
<h2>langchain-core==1.6.2</h2>
<p>Changes since langchain-core==1.6.1</p>
<p>release(core): 1.6.2 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40209">#40209</a>)
feat(openai): support async tools (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40208">#40208</a>)
chore(deps): bump mistune from 3.3.0 to 3.3.3 in /libs/core (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40150">#40150</a>)
chore(deps): bump tornado from 6.5.7 to 6.5.8 in /libs/core (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40113">#40113</a>)
fix(core): avoid mutation in google-genai standard content (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40023">#40023</a>)
fix(core): avoid mutation in bedrock converse standard content (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40022">#40022</a>)</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langchain/commit/c5ab14d42a3e22865c9def909de0b11d70b0bbf0"><code>c5ab14d</code></a>
release(core): 1.6.5 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40816">#40816</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/5704d9d4813f8c0527f04e2662cf313e1350f96f"><code>5704d9d</code></a>
chore(model-profiles): refresh model profile data (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40804">#40804</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/7622d3dce760ac4be6d9aef4c653277e06064aea"><code>7622d3d</code></a>
release(openai): 1.6.6 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40800">#40800</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/2dd956b8add667dac4f97605ae441d75b8ae228e"><code>2dd956b</code></a>
docs(infra): fix AGENTS.md root setup guidance and package doc accuracy
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40794">#40794</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/49f4b4016b82513c3dc1623bf3daa10453861621"><code>49f4b40</code></a>
fix(openai): raise on error events in stream path (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40791">#40791</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/19cadaa1a1e0cac71f3148e2f18b414dcab17426"><code>19cadaa</code></a>
fix(core): abbreviate long tool IDs in XML buffer strings (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40792">#40792</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/798441e8b07e88e79db355db452cd9492f9628f2"><code>798441e</code></a>
chore(anthropic): fix integration test cassette (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40790">#40790</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/a476942bac3fe5e521676d0f53fabafcb7ba71b1"><code>a476942</code></a>
release(openai): 1.6.5 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40787">#40787</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/46c6bdf1b4e23028a5acc060d8b2797dbf200291"><code>46c6bdf</code></a>
release(anthropic): 1.7.4 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40786">#40786</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/290dabaff27ee379920d55d155d5055d2fe29cc8"><code>290daba</code></a>
fix(anthropic): add Opus 5.5 and GPT-6 profile augmentations (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/40785">#40785</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langchain/compare/langchain-core==1.6.1...langchain-core==1.6.5">compare
view</a></li>
</ul>
</details>
<br />

Updates `pytest-mock` from 3.15.1 to 3.16.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest-mock/releases">pytest-mock's
releases</a>.</em></p>
<blockquote>
<h2>v3.16.0</h2>
<p><em>2026-09-27</em></p>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/pull/604">#604</a>:
Fixed <code>duplicate_iterators=True</code> for async functions spied
with <code>mocker.spy</code>.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/pull/611">#611</a>:
Fixed async mock assertion introspection to use awaited arguments
instead of the latest call's arguments.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/pull/606">#606</a>:
<code>mocker.resetall(return_value=True, side_effect=True)</code> now
also applies to non-callable mocks, such as those returned by
<code>mocker.create_autospec(SomeClass, instance=True)</code>.
Previously both arguments were silently ignored for them.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/547">#547</a>:
Added <code>SpyType</code> for annotating <code>mocker.spy</code>
results.</li>
<li>Dropped support for EOL Python 3.9.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/147">#147</a>:
Removed handling of <code>RuntimeError: stop called on unstarted
patcher</code>, which can no longer occur in the supported Python
versions.</li>
<li>Added support for Python 3.15.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst">pytest-mock's
changelog</a>.</em></p>
<blockquote>
<h2>3.16.0</h2>
<p><em>2026-09-27</em></p>
<ul>
<li><code>[#604](https://github.com/pytest-dev/pytest-mock/issues/604)
&lt;https://github.com/pytest-dev/pytest-mock/pull/604&gt;</code>_:
Fixed <code>duplicate_iterators=True</code> for async functions spied
with <code>mocker.spy</code>.</li>
<li><code>[#611](https://github.com/pytest-dev/pytest-mock/issues/611)
&lt;https://github.com/pytest-dev/pytest-mock/pull/611&gt;</code>_:
Fixed async mock assertion introspection to use awaited arguments
instead of the latest call's arguments.</li>
<li><code>[#606](https://github.com/pytest-dev/pytest-mock/issues/606)
&lt;https://github.com/pytest-dev/pytest-mock/pull/606&gt;</code>_:
<code>mocker.resetall(return_value=True, side_effect=True)</code> now
also applies to non-callable mocks, such as those returned by
<code>mocker.create_autospec(SomeClass, instance=True)</code>.
Previously both arguments were silently ignored for them.</li>
<li><code>[#547](https://github.com/pytest-dev/pytest-mock/issues/547)
&lt;https://github.com/pytest-dev/pytest-mock/issues/547&gt;</code>_:
Added <code>SpyType</code> for annotating <code>mocker.spy</code>
results.</li>
<li>Dropped support for EOL Python 3.9.</li>
<li><code>[#147](https://github.com/pytest-dev/pytest-mock/issues/147)
&lt;https://github.com/pytest-dev/pytest-mock/issues/147&gt;</code>_:
Removed handling of <code>RuntimeError: stop called on unstarted
patcher</code>, which can no longer occur in the supported Python
versions.</li>
<li>Added support for Python 3.15.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/f3b531f93c6d9837edc87ea1a6f4324dc9a2cdf3"><code>f3b531f</code></a>
Release 3.16.0</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/71ed67309520be160f3e100368705b58758d237a"><code>71ed673</code></a>
Fix duplicate_iterators for async spies (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/604">#604</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/0797e3d303cc5bbe0a3514b0625f7aeb3fa350b0"><code>0797e3d</code></a>
Fix async assertion argument introspection (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/611">#611</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/e24c334d573cfbf6989a31f4e3346676d9d31598"><code>e24c334</code></a>
docs: import os in the opening usage example (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/612">#612</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/9e7eb7b59cde362c1c8ace2d18ca00fe2d7a1cd1"><code>9e7eb7b</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/613">#613</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/445fd4d3daa8ed4c6d5428a77880da2e03d2f721"><code>445fd4d</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/610">#610</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/a8bd0b147afdf6b4bb1a1a3c3c088f32b0240091"><code>a8bd0b1</code></a>
Honour resetall() arguments for non-callable mocks (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/606">#606</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/6559fdfd5b67f096423e604a3a5a7045db2486a0"><code>6559fdf</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/608">#608</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/466d026254c949a8fbba8626b894308827be81cf"><code>466d026</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/605">#605</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/164defebde25bc31d53a2a64943c5c9aac43b57e"><code>164defe</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/603">#603</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest-mock/compare/v3.15.1...v3.16.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `syrupy` from 6.0.0 to 6.1.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/releases">syrupy's
releases</a>.</em></p>
<blockquote>
<h2>v6.1.1</h2>
<blockquote>
<p><strong>Note:</strong> 6.1.0 was skipped due to a CI issue. Use
<strong>6.1.1</strong>.</p>
</blockquote>
<h3>Experimental <code>--snapshot-file-lock</code> for pytest-xdist</h3>
<p><code>--snapshot-update</code> under pytest-xdist can race when
multiple workers rewrite the same multi-entry amber (<code>.ambr</code>)
file, silently dropping snapshots (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1237">#1237</a>).</p>
<p>This release adds an <strong>experimental</strong> opt-in:</p>
<ul>
<li><code>--snapshot-file-lock</code> — exclusive file lock + atomic
replace around amber writes</li>
<li><code>--snapshot-file-lock-timeout</code> — max wait for the lock
(default <strong>60s</strong>)</li>
</ul>
<p>Same-machine workers only; not reliable across remote workers / NFS.
See <a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1239">#1239</a>.</p>
<blockquote>
<p><strong>Callout for pytest-xdist users:</strong> please try
<code>--snapshot-file-lock</code> with <code>--snapshot-update</code>
and <a href="https://github.com/syrupy-project/syrupy/issues">open an
issue</a> if you hit problems. Locking is expected to become the default
in a future minor release.</p>
</blockquote>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/shipbyaeron"><code>@​shipbyaeron</code></a>
made their first contribution in <a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1">https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/syrupy-project/syrupy/blob/main/CHANGELOG.md">syrupy's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/syrupy-project/syrupy/releases/tag/v6.1.1">v6.1.1</a>
(2026-09-13)</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update dependency ruff to v0.16.4 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1225">syrupy-project/syrupy#1225</a></li>
<li>chore(deps): update dependency pytest-benchmark to v5.3.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1226">syrupy-project/syrupy#1226</a></li>
<li>chore(deps): update dependency ruff to v0.16.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1227">syrupy-project/syrupy#1227</a></li>
<li>chore(deps): update dependency pydantic to v2.13.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1228">syrupy-project/syrupy#1228</a></li>
<li>chore(deps): update dependency coverage to v7.16.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1229">syrupy-project/syrupy#1229</a></li>
<li>chore(deps): update dependency hypothesis to v6.166.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1230">syrupy-project/syrupy#1230</a></li>
<li>chore(deps): update dependency hypothesis to v6.167.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1231">syrupy-project/syrupy#1231</a></li>
<li>chore(deps): update dependency hypothesis to v6.167.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1232">syrupy-project/syrupy#1232</a></li>
<li>chore(deps): update actions/deploy-pages action to v5.0.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1234">syrupy-project/syrupy#1234</a></li>
<li>chore(deps): update dependency ruff to v0.16.6 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1235">syrupy-project/syrupy#1235</a></li>
<li>test: add coverage for read_snapshot_data_from_location returning
None by <a
href="https://github.com/shipbyaeron"><code>@​shipbyaeron</code></a> in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li>
<li>chore(deps): update dependency hypothesis to v6.168.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1238">syrupy-project/syrupy#1238</a></li>
<li>fix: opt-in file lock for concurrent amber writes under xdist by <a
href="https://github.com/noahnu"><code>@​noahnu</code></a> in <a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1239">syrupy-project/syrupy#1239</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/shipbyaeron"><code>@​shipbyaeron</code></a>
made their first contribution in <a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1">https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1</a></p>
<h2><a
href="https://github.com/syrupy-project/syrupy/releases/tag/v6.1.0">v6.1.0</a>
(2026-09-13)</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update dependency ruff to v0.16.4 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1225">syrupy-project/syrupy#1225</a></li>
<li>chore(deps): update dependency pytest-benchmark to v5.3.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1226">syrupy-project/syrupy#1226</a></li>
<li>chore(deps): update dependency ruff to v0.16.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1227">syrupy-project/syrupy#1227</a></li>
<li>chore(deps): update dependency pydantic to v2.13.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1228">syrupy-project/syrupy#1228</a></li>
<li>chore(deps): update dependency coverage to v7.16.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1229">syrupy-project/syrupy#1229</a></li>
<li>chore(deps): update dependency hypothesis to v6.166.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1230">syrupy-project/syrupy#1230</a></li>
<li>chore(deps): update dependency hypothesis to v6.167.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1231">syrupy-project/syrupy#1231</a></li>
<li>chore(deps): update dependency hypothesis to v6.167.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1232">syrupy-project/syrupy#1232</a></li>
<li>chore(deps): update actions/deploy-pages action to v5.0.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1234">syrupy-project/syrupy#1234</a></li>
<li>chore(deps): update dependency ruff to v0.16.6 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1235">syrupy-project/syrupy#1235</a></li>
<li>test: add coverage for read_snapshot_data_from_location returning
None by <a
href="https://github.com/shipbyaeron"><code>@​shipbyaeron</code></a> in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li>
<li>chore(deps): update dependency hypothesis to v6.168.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1238">syrupy-project/syrupy#1238</a></li>
<li>fix: opt-in file lock for concurrent amber writes under xdist by <a
href="https://github.com/noahnu"><code>@​noahnu</code></a> in <a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1239">syrupy-project/syrupy#1239</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/shipbyaeron"><code>@​shipbyaeron</code></a>
made their first contribution in <a
href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.0">https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/2d251e73f1ebe47fe83ed71d835d3ae8580e8313"><code>2d251e7</code></a>
chore(release): 6.1.1 [skip ci]</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/9b64ec05752586c45d1097e9d25f9ee1d4e93219"><code>9b64ec0</code></a>
chore(release): 6.1.0 [skip ci]</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/5b4256eac8720075f25b0fa8491f75948001b983"><code>5b4256e</code></a>
fix: opt-in file lock for concurrent amber writes under xdist (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1239">#1239</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/d4cb1513b5d2b1b18c3b407150db22d2d8604ddd"><code>d4cb151</code></a>
chore(deps): update dependency hypothesis to v6.168.0 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1238">#1238</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/16c4cb5b8785d89e49b8076a99f58d810e02fcce"><code>16c4cb5</code></a>
test: add coverage for read_snapshot_data_from_location returning None
(<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1236">#1236</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/2e1d3ba0d39a1d87735213a32de9dd9cdb929690"><code>2e1d3ba</code></a>
chore(deps): update dependency ruff to v0.16.6 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1235">#1235</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/fcc929d4deb2302f2d37e6511015ef43a0841bc2"><code>fcc929d</code></a>
chore(deps): update actions/deploy-pages action to v5.0.1 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1234">#1234</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/4f1bad75777ecc9d916a648dd3669b2844d08f7d"><code>4f1bad7</code></a>
chore(deps): update dependency hypothesis to v6.167.1 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1232">#1232</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/24eda28579f5761cbc64713ffcee41cc73602010"><code>24eda28</code></a>
chore(deps): update dependency hypothesis to v6.167.0 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1231">#1231</a>)</li>
<li><a
href="https://github.com/syrupy-project/syrupy/commit/0d7e46f9431e07810da4ef90dbe861b85fbc8469"><code>0d7e46f</code></a>
chore(deps): update dependency hypothesis to v6.166.0 (<a
href="https://redirect.github.com/syrupy-project/syrupy/issues/1230">#1230</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.5 to 0.16.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.9</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-24.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Avoid false positives for overloaded division
(<code>RUF069</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bugbear</code>] Avoid false positives for calls with
keyword arguments (<code>B009</code>, <code>B010</code>,
<code>B043</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in
deferred annotations (<code>TID255</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Update LibCST-based fixes for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li>
<li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message
(<code>PYI002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Fix horizontal overflow on the rules documentation page (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li>
<li>Update rules table with category information (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li>
<li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code>
checks return types in addition to arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li>
<li>[<code>flake8-bugbear</code>] Document type-checker interaction
(<code>B010</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li>
<li>[<code>flake8-comprehensions</code>] Document
<code>map</code>/generator exception behavior (<code>C417</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li>
<li>[<code>ruff</code>] Mention related isort settings
(<code>RUF022</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/qinpei-dev"><code>@​qinpei-dev</code></a></li>
<li><a
href="https://github.com/sanjayrohith"><code>@​sanjayrohith</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/webdevsamran"><code>@​webdevsamran</code></a></li>
<li><a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a></li>
<li><a
href="https://github.com/ewdurbin"><code>@​ewdurbin</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/spaceone"><code>@​spaceone</code></a></li>
<li><a
href="https://github.com/IbrahimKhan12"><code>@​IbrahimKhan12</code></a></li>
<li><a
href="https://github.com/devtechedge"><code>@​devtechedge</code></a></li>
<li><a
href="https://github.com/GruffElixir"><code>@​GruffElixir</code></a></li>
</ul>
<h2>Install ruff 0.16.9</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.16.9/ruff-installer.sh
| sh
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.9</h2>
<p>Released on 2026-09-24.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Avoid false positives for overloaded division
(<code>RUF069</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bugbear</code>] Avoid false positives for calls with
keyword arguments (<code>B009</code>, <code>B010</code>,
<code>B043</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in
deferred annotations (<code>TID255</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Update LibCST-based fixes for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li>
<li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message
(<code>PYI002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Fix horizontal overflow on the rules documentation page (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li>
<li>Update rules table with category information (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li>
<li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code>
checks return types in addition to arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li>
<li>[<code>flake8-bugbear</code>] Document type-checker interaction
(<code>B010</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li>
<li>[<code>flake8-comprehensions</code>] Document
<code>map</code>/generator exception behavior (<code>C417</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li>
<li>[<code>ruff</code>] Mention related isort settings
(<code>RUF022</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/qinpei-dev"><code>@​qinpei-dev</code></a></li>
<li><a
href="https://github.com/sanjayrohith"><code>@​sanjayrohith</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/webdevsamran"><code>@​webdevsamran</code></a></li>
<li><a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a></li>
<li><a
href="https://github.com/ewdurbin"><code>@​ewdurbin</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/spaceone"><code>@​spaceone</code></a></li>
<li><a
href="https://github.com/IbrahimKhan12"><code>@​IbrahimKhan12</code></a></li>
<li><a
href="https://github.com/devtechedge"><code>@​devtechedge</code></a></li>
<li><a
href="https://github.com/GruffElixir"><code>@​GruffElixir</code></a></li>
</ul>
<h2>0.16.8</h2>
<p>Released on 2026-09-16.</p>
<h3>Bug fixes</h3>
<ul>
<li>Visit functional <code>TypedDict</code> keyword arguments correctly
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28584">#28584</a>)</li>
<li>[<code>flake8-simplify</code>] Detect nested <code>async with</code>
under sync parent (<code>SIM117</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27821">#27821</a>)</li>
<li>[<code>flake8-simplify</code>] Preserve operand order in
<code>SIM109</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27824">#27824</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/0be08a206f9c3180afd3e93bcc792ed5cb1f4db1"><code>0be08a2</code></a>
Bump version to 0.16.9 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28882">#28882</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b4920b72b354e7c715ab861ae23458874683bb02"><code>b4920b7</code></a>
Rename <code>ruff_cli</code> to <code>ruff_command_line</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28881">#28881</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/47c751b95908a4d1f95f9ef8723036aae9da0b18"><code>47c751b</code></a>
Update dependency astral-sh/uv to v0.12.18 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28880">#28880</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/8c244e56a1aeac31c26d2371ef26588e0632235c"><code>8c244e5</code></a>
[<code>flake8-comprehensions</code>] Document <code>map</code>/generator
exception behavior (<code>C417</code>...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/5edf5a1d0a84663079e46983216059f06acea87d"><code>5edf5a1</code></a>
Use <code>target</code> form in <code>rooster.version_files</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28876">#28876</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/915bb2b4bf9ae7eee47cf55646bbfebae254a23b"><code>915bb2b</code></a>
[ty] Prefer existing @ paths over response files in Ruff and ty (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28877">#28877</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/4710e1aa962b13720cf64aa84eb279c5333896d7"><code>4710e1a</code></a>
ci(github): update version number in placeholder of issue template (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28871">#28871</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/eedfc62a75bf1ba86d48959b00eea75ae87eadca"><code>eedfc62</code></a>
[ty] Propagate outer type context through cast calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28855">#28855</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ceaa6a00830e1e350b8a23977a1a10ac467920a1"><code>ceaa6a0</code></a>
[ty] Contain rendered code within Markdown fences (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28869">#28869</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/dba0f30615424b94f94a174bba6ce6cce4bf11ff"><code>dba0f30</code></a>
authorize ruff-pre-commit dispatch via OIDC (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28867">#28867</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.5...0.16.9">compare
view</a></li>
</ul>
</details>
<br />

Updates `ty` from 0.0.75 to 0.0.84
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ty/releases">ty's
releases</a>.</em></p>
<blockquote>
<h2>0.0.84</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-24.</p>
<p>This release addresses <a
href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>,
a use-after-free vulnerability during incremental type checking that can
result in arbitrary code execution when analyzing a specially crafted
Python project. Users who run ty on untrusted code should upgrade to
0.0.84 or newer.</p>
<h3>Bug fixes</h3>
<ul>
<li>Fix stale diagnostics from the LSP server after toggling
<code>showSyntaxErrors</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li>
</ul>
<h3>LSP server</h3>
<ul>
<li>Complete string keys from dictionary initializers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li>
<li>Support LSP requests against closed documents (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li>
<li>Select projects for external files using import search paths (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li>
<li>Use workspace editor settings for external files (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid repeated subtyping checks for materialized recursive protocols
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li>
<li>Skip reading notebooks when discovering scripts (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li>
</ul>
<h3>Core type checking</h3>
<ul>
<li>Avoid incorrect simplification of <code>TypeIs</code>
materializations (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li>
<li>Fix disjointness of generic class types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li>
<li>Fix staticmethod shadowing through generic receivers and unions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li>
<li>Infer callable signatures from bounded type variables (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li>
<li>Infer constant membership in inline list and set literals (e.g.
<code>&quot;foo&quot; in [&quot;foo&quot;]</code> is now inferred as
<code>Literal[True]</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li>
<li>Infer through optional generic containers in the legacy solver (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li>
<li>Preserve call narrowing during cyclic inference (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li>
<li>Preserve intersections of type guard return types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li>
<li>Use subtyping for constraint-set implication (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li>
</ul>
<h3>Configuration</h3>
<ul>
<li>Disable <code>invalid-legacy-positional-parameter</code> by default
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Only consider reachable definitions when determining whether a
condition should be exempted from
<code>redundant-condition(-strict)</code> due to the condition being
defined relative to <code>sys.version_info</code>,
<code>sys.platform</code>, <code>os.name</code> or
<code>typing.TYPE_CHECKING</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/ibraheemdev"><code>@​ibraheemdev</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/lerebear"><code>@​lerebear</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ty/blob/main/CHANGELOG.md">ty's
changelog</a>.</em></p>
<blockquote>
<h2>0.0.84</h2>
<p>Released on 2026-09-24.</p>
<p>This release addresses <a
href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>,
a use-after-free vulnerability during incremental type checking that can
result in arbitrary code execution when analyzing a specially crafted
Python project. Users who run ty on untrusted code should upgrade to
0.0.84 or newer.</p>
<h3>Bug fixes</h3>
<ul>
<li>Fix stale diagnostics from the LSP server after toggling
<code>showSyntaxErrors</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li>
</ul>
<h3>LSP server</h3>
<ul>
<li>Complete string keys from dictionary initializers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li>
<li>Support LSP requests against closed documents (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li>
<li>Select projects for external files using import search paths (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li>
<li>Use workspace editor settings for external files (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid repeated subtyping checks for materialized recursive protocols
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li>
<li>Skip reading notebooks when discovering scripts (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li>
</ul>
<h3>Core type checking</h3>
<ul>
<li>Avoid incorrect simplification of <code>TypeIs</code>
materializations (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li>
<li>Fix disjointness of generic class types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li>
<li>Fix staticmethod shadowing through generic receivers and unions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li>
<li>Infer callable signatures from bounded type variables (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li>
<li>Infer constant membership in inline list and set literals (e.g.
<code>&quot;foo&quot; in [&quot;foo&quot;]</code> is now inferred as
<code>Literal[True]</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li>
<li>Infer through optional generic containers in the legacy solver (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li>
<li>Preserve call narrowing during cyclic inference (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li>
<li>Preserve intersections of type guard return types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li>
<li>Use subtyping for constraint-set implication (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li>
</ul>
<h3>Configuration</h3>
<ul>
<li>Disable <code>invalid-legacy-positional-parameter</code> by default
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Only consider reachable definitions when determining whether a
condition should be exempted from
<code>redundant-condition(-strict)</code> due to the condition being
defined relative to <code>sys.version_info</code>,
<code>sys.platform</code>, <code>os.name</code> or
<code>typing.TYPE_CHECKING</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/ibraheemdev"><code>@​ibraheemdev</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/lerebear"><code>@​lerebear</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/ewdurbin"><code>@​ewdurbin</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ty/commit/8dd9a7f7fa35a18275d82117e6593ba45507065f"><code>8dd9a7f</code></a>
Bump version to 0.0.84 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4585">#4585</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/d4e4bf90906c7677049bc3a29d1735de7d22052d"><code>d4e4bf9</code></a>
publish to astral-sh/versions via OIDC (<a
href="https://redirect.github.com/astral-sh/ty/issues/4581">#4581</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/94ce7333abb356b2068dc98d37a68c993da6d09b"><code>94ce733</code></a>
use oidc issued token for docs publication (<a
href="https://redirect.github.com/astral-sh/ty/issues/4579">#4579</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/901eeaa9cd9ac06f34e85e4f721f76a0dc36e217"><code>901eeaa</code></a>
Update prek dependencies (<a
href="https://redirect.github.com/astral-sh/ty/issues/4576">#4576</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/09bf0b1b2114a628f3e2296d3d9d28245066c98b"><code>09bf0b1</code></a>
Update docker/setup-buildx-action action to v4.3.0 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4575">#4575</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/89d6ffe529dd44f64adc0d28f80744b7c7ab217f"><code>89d6ffe</code></a>
Update astral-sh/setup-uv action to v10.2.0 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4574">#4574</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/9c214798cfcc59069e986876564638fadf32d774"><code>9c21479</code></a>
Bump version to 0.0.83 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4569">#4569</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/04c69110b391e96310e6892cbed9936c4f31d7aa"><code>04c6911</code></a>
Sync the ty security mirror (<a
href="https://redirect.github.com/astral-sh/ty/issues/4549">#4549</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/3fa57a25767c619dbeba697c2acfbb8eb291519a"><code>3fa57a2</code></a>
Grant the versions workflow repository read access (<a
href="https://redirect.github.com/astral-sh/ty/issues/4550">#4550</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/a15b35389b44db57f718fd4e19e093481747c53e"><code>a15b353</code></a>
use scoped token for release workflow (<a
href="https://redirect.github.com/astral-sh/ty/issues/4506">#4506</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ty/compare/0.0.75...0.0.84">compare
view</a></li>
</ul>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: John Kennedy <jkennedyvz@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-10-01 11:57:28 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>John Kennedyopen-swe[bot] <open-swe@users.noreply.github.com>
5204e60579 chore(deps-dev): bump the minor-and-patch group in /libs/checkpoint-sqlite with 3 updates (#9146)
Bumps the minor-and-patch group in /libs/checkpoint-sqlite with 3
updates: [pytest-mock](https://github.com/pytest-dev/pytest-mock),
[ruff](https://github.com/astral-sh/ruff) and
[ty](https://github.com/astral-sh/ty).

Updates `pytest-mock` from 3.15.1 to 3.16.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest-mock/releases">pytest-mock's
releases</a>.</em></p>
<blockquote>
<h2>v3.16.0</h2>
<p><em>2026-09-27</em></p>
<ul>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/pull/604">#604</a>:
Fixed <code>duplicate_iterators=True</code> for async functions spied
with <code>mocker.spy</code>.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/pull/611">#611</a>:
Fixed async mock assertion introspection to use awaited arguments
instead of the latest call's arguments.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/pull/606">#606</a>:
<code>mocker.resetall(return_value=True, side_effect=True)</code> now
also applies to non-callable mocks, such as those returned by
<code>mocker.create_autospec(SomeClass, instance=True)</code>.
Previously both arguments were silently ignored for them.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/547">#547</a>:
Added <code>SpyType</code> for annotating <code>mocker.spy</code>
results.</li>
<li>Dropped support for EOL Python 3.9.</li>
<li><a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/147">#147</a>:
Removed handling of <code>RuntimeError: stop called on unstarted
patcher</code>, which can no longer occur in the supported Python
versions.</li>
<li>Added support for Python 3.15.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst">pytest-mock's
changelog</a>.</em></p>
<blockquote>
<h2>3.16.0</h2>
<p><em>2026-09-27</em></p>
<ul>
<li><code>[#604](https://github.com/pytest-dev/pytest-mock/issues/604)
&lt;https://github.com/pytest-dev/pytest-mock/pull/604&gt;</code>_:
Fixed <code>duplicate_iterators=True</code> for async functions spied
with <code>mocker.spy</code>.</li>
<li><code>[#611](https://github.com/pytest-dev/pytest-mock/issues/611)
&lt;https://github.com/pytest-dev/pytest-mock/pull/611&gt;</code>_:
Fixed async mock assertion introspection to use awaited arguments
instead of the latest call's arguments.</li>
<li><code>[#606](https://github.com/pytest-dev/pytest-mock/issues/606)
&lt;https://github.com/pytest-dev/pytest-mock/pull/606&gt;</code>_:
<code>mocker.resetall(return_value=True, side_effect=True)</code> now
also applies to non-callable mocks, such as those returned by
<code>mocker.create_autospec(SomeClass, instance=True)</code>.
Previously both arguments were silently ignored for them.</li>
<li><code>[#547](https://github.com/pytest-dev/pytest-mock/issues/547)
&lt;https://github.com/pytest-dev/pytest-mock/issues/547&gt;</code>_:
Added <code>SpyType</code> for annotating <code>mocker.spy</code>
results.</li>
<li>Dropped support for EOL Python 3.9.</li>
<li><code>[#147](https://github.com/pytest-dev/pytest-mock/issues/147)
&lt;https://github.com/pytest-dev/pytest-mock/issues/147&gt;</code>_:
Removed handling of <code>RuntimeError: stop called on unstarted
patcher</code>, which can no longer occur in the supported Python
versions.</li>
<li>Added support for Python 3.15.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/f3b531f93c6d9837edc87ea1a6f4324dc9a2cdf3"><code>f3b531f</code></a>
Release 3.16.0</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/71ed67309520be160f3e100368705b58758d237a"><code>71ed673</code></a>
Fix duplicate_iterators for async spies (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/604">#604</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/0797e3d303cc5bbe0a3514b0625f7aeb3fa350b0"><code>0797e3d</code></a>
Fix async assertion argument introspection (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/611">#611</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/e24c334d573cfbf6989a31f4e3346676d9d31598"><code>e24c334</code></a>
docs: import os in the opening usage example (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/612">#612</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/9e7eb7b59cde362c1c8ace2d18ca00fe2d7a1cd1"><code>9e7eb7b</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/613">#613</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/445fd4d3daa8ed4c6d5428a77880da2e03d2f721"><code>445fd4d</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/610">#610</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/a8bd0b147afdf6b4bb1a1a3c3c088f32b0240091"><code>a8bd0b1</code></a>
Honour resetall() arguments for non-callable mocks (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/606">#606</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/6559fdfd5b67f096423e604a3a5a7045db2486a0"><code>6559fdf</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/608">#608</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/466d026254c949a8fbba8626b894308827be81cf"><code>466d026</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/605">#605</a>)</li>
<li><a
href="https://github.com/pytest-dev/pytest-mock/commit/164defebde25bc31d53a2a64943c5c9aac43b57e"><code>164defe</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/pytest-dev/pytest-mock/issues/603">#603</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/pytest-dev/pytest-mock/compare/v3.15.1...v3.16.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `ruff` from 0.16.5 to 0.16.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/releases">ruff's
releases</a>.</em></p>
<blockquote>
<h2>0.16.9</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-24.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Avoid false positives for overloaded division
(<code>RUF069</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bugbear</code>] Avoid false positives for calls with
keyword arguments (<code>B009</code>, <code>B010</code>,
<code>B043</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in
deferred annotations (<code>TID255</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Update LibCST-based fixes for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li>
<li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message
(<code>PYI002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Fix horizontal overflow on the rules documentation page (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li>
<li>Update rules table with category information (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li>
<li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code>
checks return types in addition to arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li>
<li>[<code>flake8-bugbear</code>] Document type-checker interaction
(<code>B010</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li>
<li>[<code>flake8-comprehensions</code>] Document
<code>map</code>/generator exception behavior (<code>C417</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li>
<li>[<code>ruff</code>] Mention related isort settings
(<code>RUF022</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/qinpei-dev"><code>@​qinpei-dev</code></a></li>
<li><a
href="https://github.com/sanjayrohith"><code>@​sanjayrohith</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/webdevsamran"><code>@​webdevsamran</code></a></li>
<li><a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a></li>
<li><a
href="https://github.com/ewdurbin"><code>@​ewdurbin</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/spaceone"><code>@​spaceone</code></a></li>
<li><a
href="https://github.com/IbrahimKhan12"><code>@​IbrahimKhan12</code></a></li>
<li><a
href="https://github.com/devtechedge"><code>@​devtechedge</code></a></li>
<li><a
href="https://github.com/GruffElixir"><code>@​GruffElixir</code></a></li>
</ul>
<h2>Install ruff 0.16.9</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/ruff/releases/download/0.16.9/ruff-installer.sh
| sh
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's
changelog</a>.</em></p>
<blockquote>
<h2>0.16.9</h2>
<p>Released on 2026-09-24.</p>
<h3>Preview features</h3>
<ul>
<li>[<code>ruff</code>] Avoid false positives for overloaded division
(<code>RUF069</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>[<code>flake8-bugbear</code>] Avoid false positives for calls with
keyword arguments (<code>B009</code>, <code>B010</code>,
<code>B043</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li>
<li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in
deferred annotations (<code>TID255</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li>
</ul>
<h3>Rule changes</h3>
<ul>
<li>Update LibCST-based fixes for Python 3.15 (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li>
<li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message
(<code>PYI002</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li>Fix horizontal overflow on the rules documentation page (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li>
<li>Update rules table with category information (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li>
<li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code>
checks return types in addition to arguments (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li>
<li>[<code>flake8-bugbear</code>] Document type-checker interaction
(<code>B010</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li>
<li>[<code>flake8-comprehensions</code>] Document
<code>map</code>/generator exception behavior (<code>C417</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li>
<li>[<code>ruff</code>] Mention related isort settings
(<code>RUF022</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/qinpei-dev"><code>@​qinpei-dev</code></a></li>
<li><a
href="https://github.com/sanjayrohith"><code>@​sanjayrohith</code></a></li>
<li><a href="https://github.com/ntBre"><code>@​ntBre</code></a></li>
<li><a
href="https://github.com/webdevsamran"><code>@​webdevsamran</code></a></li>
<li><a
href="https://github.com/zaniebot"><code>@​zaniebot</code></a></li>
<li><a
href="https://github.com/ewdurbin"><code>@​ewdurbin</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/spaceone"><code>@​spaceone</code></a></li>
<li><a
href="https://github.com/IbrahimKhan12"><code>@​IbrahimKhan12</code></a></li>
<li><a
href="https://github.com/devtechedge"><code>@​devtechedge</code></a></li>
<li><a
href="https://github.com/GruffElixir"><code>@​GruffElixir</code></a></li>
</ul>
<h2>0.16.8</h2>
<p>Released on 2026-09-16.</p>
<h3>Bug fixes</h3>
<ul>
<li>Visit functional <code>TypedDict</code> keyword arguments correctly
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28584">#28584</a>)</li>
<li>[<code>flake8-simplify</code>] Detect nested <code>async with</code>
under sync parent (<code>SIM117</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27821">#27821</a>)</li>
<li>[<code>flake8-simplify</code>] Preserve operand order in
<code>SIM109</code> fix (<a
href="https://redirect.github.com/astral-sh/ruff/pull/27824">#27824</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ruff/commit/0be08a206f9c3180afd3e93bcc792ed5cb1f4db1"><code>0be08a2</code></a>
Bump version to 0.16.9 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28882">#28882</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/b4920b72b354e7c715ab861ae23458874683bb02"><code>b4920b7</code></a>
Rename <code>ruff_cli</code> to <code>ruff_command_line</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28881">#28881</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/47c751b95908a4d1f95f9ef8723036aae9da0b18"><code>47c751b</code></a>
Update dependency astral-sh/uv to v0.12.18 (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28880">#28880</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/8c244e56a1aeac31c26d2371ef26588e0632235c"><code>8c244e5</code></a>
[<code>flake8-comprehensions</code>] Document <code>map</code>/generator
exception behavior (<code>C417</code>...</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/5edf5a1d0a84663079e46983216059f06acea87d"><code>5edf5a1</code></a>
Use <code>target</code> form in <code>rooster.version_files</code> (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28876">#28876</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/915bb2b4bf9ae7eee47cf55646bbfebae254a23b"><code>915bb2b</code></a>
[ty] Prefer existing @ paths over response files in Ruff and ty (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28877">#28877</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/4710e1aa962b13720cf64aa84eb279c5333896d7"><code>4710e1a</code></a>
ci(github): update version number in placeholder of issue template (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28871">#28871</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/eedfc62a75bf1ba86d48959b00eea75ae87eadca"><code>eedfc62</code></a>
[ty] Propagate outer type context through cast calls (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28855">#28855</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/ceaa6a00830e1e350b8a23977a1a10ac467920a1"><code>ceaa6a0</code></a>
[ty] Contain rendered code within Markdown fences (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28869">#28869</a>)</li>
<li><a
href="https://github.com/astral-sh/ruff/commit/dba0f30615424b94f94a174bba6ce6cce4bf11ff"><code>dba0f30</code></a>
authorize ruff-pre-commit dispatch via OIDC (<a
href="https://redirect.github.com/astral-sh/ruff/issues/28867">#28867</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ruff/compare/0.16.5...0.16.9">compare
view</a></li>
</ul>
</details>
<br />

Updates `ty` from 0.0.75 to 0.0.84
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ty/releases">ty's
releases</a>.</em></p>
<blockquote>
<h2>0.0.84</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-24.</p>
<p>This release addresses <a
href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>,
a use-after-free vulnerability during incremental type checking that can
result in arbitrary code execution when analyzing a specially crafted
Python project. Users who run ty on untrusted code should upgrade to
0.0.84 or newer.</p>
<h3>Bug fixes</h3>
<ul>
<li>Fix stale diagnostics from the LSP server after toggling
<code>showSyntaxErrors</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li>
</ul>
<h3>LSP server</h3>
<ul>
<li>Complete string keys from dictionary initializers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li>
<li>Support LSP requests against closed documents (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li>
<li>Select projects for external files using import search paths (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li>
<li>Use workspace editor settings for external files (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid repeated subtyping checks for materialized recursive protocols
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li>
<li>Skip reading notebooks when discovering scripts (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li>
</ul>
<h3>Core type checking</h3>
<ul>
<li>Avoid incorrect simplification of <code>TypeIs</code>
materializations (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li>
<li>Fix disjointness of generic class types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li>
<li>Fix staticmethod shadowing through generic receivers and unions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li>
<li>Infer callable signatures from bounded type variables (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li>
<li>Infer constant membership in inline list and set literals (e.g.
<code>&quot;foo&quot; in [&quot;foo&quot;]</code> is now inferred as
<code>Literal[True]</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li>
<li>Infer through optional generic containers in the legacy solver (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li>
<li>Preserve call narrowing during cyclic inference (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li>
<li>Preserve intersections of type guard return types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li>
<li>Use subtyping for constraint-set implication (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li>
</ul>
<h3>Configuration</h3>
<ul>
<li>Disable <code>invalid-legacy-positional-parameter</code> by default
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Only consider reachable definitions when determining whether a
condition should be exempted from
<code>redundant-condition(-strict)</code> due to the condition being
defined relative to <code>sys.version_info</code>,
<code>sys.platform</code>, <code>os.name</code> or
<code>typing.TYPE_CHECKING</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/ibraheemdev"><code>@​ibraheemdev</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/lerebear"><code>@​lerebear</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/ty/blob/main/CHANGELOG.md">ty's
changelog</a>.</em></p>
<blockquote>
<h2>0.0.84</h2>
<p>Released on 2026-09-24.</p>
<p>This release addresses <a
href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>,
a use-after-free vulnerability during incremental type checking that can
result in arbitrary code execution when analyzing a specially crafted
Python project. Users who run ty on untrusted code should upgrade to
0.0.84 or newer.</p>
<h3>Bug fixes</h3>
<ul>
<li>Fix stale diagnostics from the LSP server after toggling
<code>showSyntaxErrors</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li>
</ul>
<h3>LSP server</h3>
<ul>
<li>Complete string keys from dictionary initializers (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li>
<li>Support LSP requests against closed documents (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li>
<li>Select projects for external files using import search paths (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li>
<li>Use workspace editor settings for external files (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Avoid repeated subtyping checks for materialized recursive protocols
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li>
<li>Skip reading notebooks when discovering scripts (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li>
</ul>
<h3>Core type checking</h3>
<ul>
<li>Avoid incorrect simplification of <code>TypeIs</code>
materializations (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li>
<li>Fix disjointness of generic class types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li>
<li>Fix staticmethod shadowing through generic receivers and unions (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li>
<li>Infer callable signatures from bounded type variables (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li>
<li>Infer constant membership in inline list and set literals (e.g.
<code>&quot;foo&quot; in [&quot;foo&quot;]</code> is now inferred as
<code>Literal[True]</code>) (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li>
<li>Infer through optional generic containers in the legacy solver (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li>
<li>Preserve call narrowing during cyclic inference (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li>
<li>Preserve intersections of type guard return types (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li>
<li>Use subtyping for constraint-set implication (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li>
</ul>
<h3>Configuration</h3>
<ul>
<li>Disable <code>invalid-legacy-positional-parameter</code> by default
(<a
href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li>
</ul>
<h3>Other changes</h3>
<ul>
<li>Only consider reachable definitions when determining whether a
condition should be exempted from
<code>redundant-condition(-strict)</code> due to the condition being
defined relative to <code>sys.version_info</code>,
<code>sys.platform</code>, <code>os.name</code> or
<code>typing.TYPE_CHECKING</code> (<a
href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li>
</ul>
<h3>Contributors</h3>
<ul>
<li><a
href="https://github.com/ibraheemdev"><code>@​ibraheemdev</code></a></li>
<li><a href="https://github.com/zsol"><code>@​zsol</code></a></li>
<li><a
href="https://github.com/charliermarsh"><code>@​charliermarsh</code></a></li>
<li><a
href="https://github.com/lerebear"><code>@​lerebear</code></a></li>
<li><a
href="https://github.com/MichaReiser"><code>@​MichaReiser</code></a></li>
<li><a
href="https://github.com/ewdurbin"><code>@​ewdurbin</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/ty/commit/8dd9a7f7fa35a18275d82117e6593ba45507065f"><code>8dd9a7f</code></a>
Bump version to 0.0.84 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4585">#4585</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/d4e4bf90906c7677049bc3a29d1735de7d22052d"><code>d4e4bf9</code></a>
publish to astral-sh/versions via OIDC (<a
href="https://redirect.github.com/astral-sh/ty/issues/4581">#4581</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/94ce7333abb356b2068dc98d37a68c993da6d09b"><code>94ce733</code></a>
use oidc issued token for docs publication (<a
href="https://redirect.github.com/astral-sh/ty/issues/4579">#4579</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/901eeaa9cd9ac06f34e85e4f721f76a0dc36e217"><code>901eeaa</code></a>
Update prek dependencies (<a
href="https://redirect.github.com/astral-sh/ty/issues/4576">#4576</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/09bf0b1b2114a628f3e2296d3d9d28245066c98b"><code>09bf0b1</code></a>
Update docker/setup-buildx-action action to v4.3.0 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4575">#4575</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/89d6ffe529dd44f64adc0d28f80744b7c7ab217f"><code>89d6ffe</code></a>
Update astral-sh/setup-uv action to v10.2.0 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4574">#4574</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/9c214798cfcc59069e986876564638fadf32d774"><code>9c21479</code></a>
Bump version to 0.0.83 (<a
href="https://redirect.github.com/astral-sh/ty/issues/4569">#4569</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/04c69110b391e96310e6892cbed9936c4f31d7aa"><code>04c6911</code></a>
Sync the ty security mirror (<a
href="https://redirect.github.com/astral-sh/ty/issues/4549">#4549</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/3fa57a25767c619dbeba697c2acfbb8eb291519a"><code>3fa57a2</code></a>
Grant the versions workflow repository read access (<a
href="https://redirect.github.com/astral-sh/ty/issues/4550">#4550</a>)</li>
<li><a
href="https://github.com/astral-sh/ty/commit/a15b35389b44db57f718fd4e19e093481747c53e"><code>a15b353</code></a>
use scoped token for release workflow (<a
href="https://redirect.github.com/astral-sh/ty/issues/4506">#4506</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/ty/compare/0.0.75...0.0.84">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: John Kennedy <jkennedyvz@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-10-01 11:54:00 -07:00