Skip to content

fix(langgraph): use identity check for Command.update in map_command#7087

Open
Giulio Leone (giulio-leone) wants to merge 1 commit intolangchain-ai:mainfrom
giulio-leone:fix/command-update-falsy
Open

fix(langgraph): use identity check for Command.update in map_command#7087
Giulio Leone (giulio-leone) wants to merge 1 commit intolangchain-ai:mainfrom
giulio-leone:fix/command-update-falsy

Conversation

@giulio-leone

Problem

map_command() in _io.py uses a truthy check (if cmd.update:) instead of an identity check (if cmd.update is not None:) for the update field. This silently drops falsy but valid state updates:

Command(update=0)      # update silently dropped
Command(update=False)  # update silently dropped
Command(update='')     # update silently dropped

The adjacent resume field already uses the correct pattern:

if cmd.resume is not None:     # ← correct
if cmd.update:                  # ← bug: truthy check

And _update_as_tuples() also correctly uses self.update is not None.

Fix

Changed if cmd.update: to if cmd.update is not None: to align with the rest of the codebase.

Tests

Added test_map_command.py with 10 tests verifying that:

  • Falsy but valid updates (0, False, "") are correctly propagated through map_command
  • None sentinel correctly produces no writes
  • Standard cases (dict, tuples, combined goto+update, resume+update) continue to work

@giulio-leone
Copy link
Author

✅ Verified with real graph execution

Environment: Python 3.13.12, macOS, langgraph from this branch

Bug proof — old behavior silently drops falsy updates:

from langgraph.types import Command

def old_check(cmd):  return bool(cmd.update)      # old: truthy
def new_check(cmd):  return cmd.update is not None  # new: identity

for val in [0, False, "", {"key": "val"}]:
    cmd = Command(update=val)
    print(f"Command(update={val!r}): old={old_check(cmd)}, new={new_check(cmd)}")
Command(update=0):       old=False, new=True  🐛 BUG: update silently dropped
Command(update=False):   old=False, new=True  🐛 BUG: update silently dropped
Command(update=""):      old=False, new=True  🐛 BUG: update silently dropped
Command(update={"key":…}): old=True,  new=True  ✅

Fix verified — real graph with Command(update={"counter": 0}):

from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command

def set_zero(state):
    return Command(update={"counter": 0, "messages": ["reset"]})

# ... graph setup ...
result = app.invoke({"counter": 100, "messages": ["start"]})
Final counter: 0  ✅  (would be 101 without fix — update dropped, only increment applied)
Messages: ["start", "incremented", "reset"]  ✅

The fix aligns cmd.update with the existing cmd.resume is not None pattern on the adjacent line.

@giulio-leone
Copy link
Author

William FH (@hinthornw) Found this during a source audit — map_command() uses if cmd.update: (truthy check) while the adjacent cmd.resume correctly uses is not None. This silently drops valid falsy updates like Command(update=0) or Command(update=False). One-line fix + 10 unit tests. Bug proof and real graph execution verification above.

map_command() used a truthy check (`if cmd.update:`) instead of an
identity check (`if cmd.update is not None:`) for the update field.
This silently drops falsy but valid state updates like
Command(update=0), Command(update=False), or Command(update='').

The adjacent resume field already uses the correct pattern
(`if cmd.resume is not None:`), and _update_as_tuples() also uses
`is not None`. This aligns map_command with the rest of the codebase.
@giulio-leone
Copy link
Author

Friendly ping — this branch has been refreshed on the latest upstream base and all current review feedback has been addressed. It should be ready for review whenever you have a chance. Happy to make any further changes quickly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant