Skip to content

fix(signals): link a store reader to its derive's staged error (#4517) - #4519

Merged
ryansolid merged 2 commits into
solidjs:nextfrom
brenelz:claude/issue-4517
Oct 31, 2026
Merged

ryansolid merged 2 commits into
solidjs:nextfrom
brenelz:claude/issue-4517

Conversation

@brenelz

@brenelz brenelz commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Fixes #4517.

An <Errored> mounted in the same change that errors its content stayed on its fallback after the next answer landed, when its content read a keyed createProjection over a memo. Reading the memo directly recovered. This regressed in #4456.

#4456's stageMark marks a derive with CONFIG_STAGED_ERROR but sets no STATUS_ERROR until the commit. pullFamily linked a reader to the derive only when the derive was pending or errored, so it pulled a staged-error derive untracked. The pull threw before any leaf was read, the reader subscribed to nothing in the family, and the landing never reached it.

pullFamily now links the reader to a derive that carries a staged error, the same way it links to a pending or errored derive, so the reader re-runs at the landing. The render-effect early return in that branch now requires STATUS_PENDING. For pending and errored derives this is the same condition. A frame reader of a held derive with a staged error now reads it and meets the error, which derived-refetch-error-3887 requires. The staged-error marking from #4456 is unchanged.

Open: the frame-rule comment above the early return describes only pending and errored derives. It may need a ruling on whether staged errors belong to it.

How did you test this change?

  • cd packages/signals && npx vitest run tests/errored-born-staged-error-projection-4517.test.ts: the projection case fails on next and passes with the fix.
  • cd packages/web && npx vitest run test/errored-born-staged-error-projection-4517.spec.tsx: the issue's repro. The keyed case fails on next with "too short".
  • Full suites: signals (424 files), solid (917 tests), web client, hydrate and server all pass, except server-functions-adapter-request.spec.tsx, which fails the same way on next.
  • Size: the store scenarios grow by 8 to 10 B minified, all under their caps.

…js#4517)

A derive marked with a staged error (`stageMark`, solidjs#4456) carries no
STATUS_ERROR until the commit, so `pullFamily` took it for a settled
derive and pulled it untracked. The pull threw the staged error before
the reader read any leaf, so the reader subscribed to nothing in the
family: when the derive's source re-asked and landed, neither the wake
nor the settle reached it. An `<Errored>` mounted in the change that
errored its content stayed on its fallback over a keyed
`createProjection`, while the same read of the memo recovered.

A reader now links to a derive carrying a staged error as it does to a
pending or errored one, and re-runs at the landing. The render-effect
early return in that branch is for a derive with a flight up only: a
staged error is an answer the frame reader has to meet (D-41; the solidjs#3887
pin).

Pins: packages/signals/tests/errored-born-staged-error-projection-4517.test.ts,
packages/web/test/errored-born-staged-error-projection-4517.spec.tsx
(the issue's repro).

Size: +8 to +10 B minified on the store scenarios, every one under its
brotli cap; the three over-cap warnings are +0 B over next.
The pullFamily comment block keeps its original lines, with one line on
the staged-error pull in place of the three that narrated the issue.
The web spec's header keeps only the jsxImportSource and
vitest-environment pragmas, as the neighbouring specs do. The changeset
states the behavior that changed in two sentences.
@changeset-bot

changeset-bot Bot commented Oct 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0d540e5

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

This PR includes changesets to release 15 packages
Name Type
@solidjs/signals Patch
test-integration Patch
@solidjs/web Patch
@solidjs/babel-plugin Patch
@solidjs/compiler Patch
@solidjs/diagnostics Patch
@solidjs/element Patch
@solidjs/h Patch
@solidjs/html Patch
solid-js Patch
@solidjs/universal Patch
board-example Patch
canvas-example Patch
server-dbmon-example Patch
todos-server-example 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

@codspeed

codspeed Bot commented Oct 31, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 11.03%

2 warnings

⚠️ 3 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ 1 benchmark with a significant change ran on different hardware

Its base and head results were measured on machines with a different CPU, core count or memory, so the change might not come from the code. Run base and head on the same runner type.

Learn more about Macro Runners

See affected benchmarks

❌ 1 regressed benchmark
✅ 199 untouched benchmarks
⏩ 5 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ projection derive: write one NESTED field (reference) 2.1 ms 2.4 ms -11.03%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing brenelz:claude/issue-4517 (0d540e5) with next (6bde511)

Open in CodSpeed

Footnotes

  1. 5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@ryansolid
ryansolid merged commit 25b94f0 into solidjs:next Oct 31, 2026
8 of 9 checks passed

Copy link
Copy Markdown
Member

Thanks, @brenelz! Merged as 25b94f0. Two independent reviews agreed, and the PENDING-only early return checks out by D-3/D-41.


Generated by Claude Code

ryansolid added a commit that referenced this pull request Oct 31, 2026
ryansolid added a commit that referenced this pull request Oct 31, 2026
…rror (#4527) (#4533)

* fix(signals): an effect's error boundary keeps no superseded staged error (#4527)

Here is the case: an action re-asks a derived store and a memo, so its
transition stays open. The store's re-ask is rejected (staged, D-41), and a
second re-ask answers before the commit. An effect that created
`createErrorBoundary(() => store, ...)` in its compute got the fallback at
the commit and never ran again.

- store: handleAsync's untracked shape probe of a returned proxy pulls the
  derive. When that pull throws a staged error, it now links the pass, as a
  tracked read does (#4519). The memo carries the error and stays reachable
  by the re-ask and the answer that supersede it.
- boundaries: prune's "fresh boundary keeps its fallback until the reader
  commits" clause (#3540) applies to loading boundaries only. In an error
  boundary, a recovery that lands in the hold that staged the error joins
  that hold and reveals with its commit (D-39, D-41).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2

* fix(signals): trim the #4527 fix by 11 B minified on store rows, 4 B elsewhere

- store: link the pass the staged error is thrown into whether the pull is
  tracked or not (a tracked read links anyway, and `link` dedupes). This
  drops the `tracking` test, and `c &&` replaces `c !== null`.
- boundaries: an error boundary is born `_initialized` (the field is
  loading-only: no other error-boundary path reads it), so prune's #3540
  clause stays as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2

---------

Co-authored-by: Claude <noreply@anthropic.com>
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