Skip to content

fix(core): round-trip dicts that carry the serde marker key - #934

Open
sclfcz wants to merge 1 commit into
apache:mainfrom
sclfcz:fix/serde-marker-key-collision
Open

sclfcz wants to merge 1 commit into
apache:mainfrom
sclfcz:fix/serde-marker-key-collision

Conversation

@sclfcz

@sclfcz sclfcz commented Sep 18, 2026

Copy link
Copy Markdown

serde.deserialize treats any dict that carries __burr_serde__ as a serde envelope:

from burr.core.serde import KEY, serialize, deserialize

deserialize(serialize({KEY: "hello"}))
# ValueError: No deserializer registered for key: 'hello'. Registered keys: []

serialize_dict passes an ordinary dict through unchanged, so an application value that happens to use that key — at any nesting depth — cannot be read back. Through State.serialize/State.deserialize it shows up as a state field that cannot be restored at all:

Failed to deserialize state field 'payload': No deserializer registered for key: 'hello'

The key is not documented as reserved anywhere, so nothing tells an application to avoid it.

What this changes

A plain dict whose keys include the marker is wrapped in an envelope that restores it verbatim. Every other dict keeps exactly the serialized form it has today, so previously saved states are unaffected, and a real envelope still dispatches to its deserializer — or still raises the existing "make sure the module registering the deserializer has been imported" error when it has not been imported.

How this was checked

  • New tests in tests/core/test_serde.py: a nested dict containing the marker round-trips, State containing one deserializes, and an envelope whose deserializer was never imported still raises the informative error. The first two fail on main, the third passes on both.
  • Manually checked that a registered deserializer still receives its envelope, that a dict containing both the marker and the payload key round-trips, and that a marker value of "burr.dict" round-trips.
  • tests/core → 399 passed (test_graphviz_display.py needs the dot binary, which is not installed here), tests/integrations/serde → 15 passed.
  • black --line-length=100, isort and flake8 at the versions pinned in .pre-commit-config.yaml.

serialize_dict passed an ordinary dict through unchanged, so a dict whose own
keys include __burr_serde__ was read back as a serde envelope. deserialize then
raised "No deserializer registered for key", which surfaced through
State.deserialize as a state field that cannot be restored. The key is not
documented as reserved.

Wrap such a dict in an envelope that restores it verbatim; every other dict
keeps its serialized form, and real envelopes still dispatch (or still raise
the informative error when their module was not imported).
@github-actions github-actions Bot added the area/core Application, State, Graph, Actions label Sep 18, 2026

This branch has not been deployed

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

Labels

area/core Application, State, Graph, Actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant