Skip to content

fix: resolve circular references through custom revivers#154

Merged
elliott-with-the-longest-name-on-github merged 3 commits into
sveltejs:mainfrom
gabrielstellini:main
Jul 18, 2026
Merged

fix: resolve circular references through custom revivers#154
elliott-with-the-longest-name-on-github merged 3 commits into
sveltejs:mainfrom
gabrielstellini:main

Conversation

@gabrielstellini

Copy link
Copy Markdown
Contributor

Fixes a regression introduced in v5.6.2 where parse() throws Invalid circular reference for valid circular structures structures that route through custom revivers (including self-referential ones).

The hydrating Set guard (added to catch infinite recursion) runs before checking whether the payload has already been hydrated. When a cycle re-encounters a custom type, the payload index is still in the hydrating Set from the outer call, so the guard throws, even though hydrate(payloadIndex) would have returned immediately from cache.

The fix adds a cache check (i in hydrated) before the guard. If the payload is already hydrated, the reviver is called directly with the cached value, bypassing the guard entirely. Genuinely invalid circular references (e.g. [["Custom", 0]] where the type points to itself as its own payload) are still rejected.

@changeset-bot

changeset-bot Bot commented May 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a9a07f5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
devalue Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gabrielstellini

Copy link
Copy Markdown
Contributor Author

@Rich-Harris Can I get a review on this please? It fixes a crash in more complex json structures

Comment thread src/parse.js Outdated
Comment thread test/index.test.js Outdated
@elliott-with-the-longest-name-on-github

Copy link
Copy Markdown
Contributor

Interesting note for the future: While I was working through this, I realized that without a WeakMap on the input payload, it's basically just impossible to have self-referential custom stuff, because (payload) => new Thing(payload) has no way of expressing that. Not like... a serious issue or anything. And definitely not new as of this change.

@elliott-with-the-longest-name-on-github
elliott-with-the-longest-name-on-github merged commit cd6da94 into sveltejs:main Jul 18, 2026
5 checks passed
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.

2 participants