fix(sdk): prevent recursive filled-host comparisons - #3861
Merged
Conversation
`sdk.host.get(...).const()` with no `map` compares whole `FilledHost` records with the default `deepEqual`. A filled address carries enumerable `nonLocal`/`public`/`bridge` getters that each return another filled address with the same getters, and `deepEqual` had no identity short-circuit, so the walk never terminated — it overflowed the stack on any pair, an object against itself included. `watchGen` only calls `eq` from the second value onward, so `const()` resolved normally and the throw waited for the first actual change. There it landed in `const()`'s rejection handler, which aborted the watch without calling `constRetry` and without logging, so a package watching a dependency's address simply stopped reacting: no restart, no error, nothing in the logs. Three fixes, each of which independently closes the failure: - `deepEqual` returns true for arguments that are already the same reference. - A filled address's helpers and derived getters are non-enumerable, so it compares, serializes and spreads as the data it wraps. - `const()`'s rejection path logs. Whatever kills a watch, it says so rather than leaving the context silently unreactive. It still aborts rather than retrying: the same path takes a failed fetch, and restarting there would spin. Found via simplex-websocket-bridge-startos, whose relays went stale after the SimpleX Server was reinstalled. `swatcher` and `i2pd-startos` have the same unmapped read today. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MattDHill
force-pushed
the
fix/host-watch-deep-equal
branch
from
August 28, 2026 20:04
19ebfb1 to
fc1a559
Compare
.const() host watches alive across a change
dr-bonez
approved these changes
Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
FilledAddressobjects exposed helper methods and derived address views as enumerable properties. Comparing two filled hosts withdeepEqualtherefore traversed the recursively derived views and could overflow the stack when a host watch received an update.This change:
deepEqualWatchable.const()subscriptionTesting