Skip to content

2.0: two async sources answered and re-asked in one tick: the second answer is dropped, latest() of their memo throws #4495

Closed

Description

@ryansolid

Two async memos m1 and m2 both answer, and then a write re-asks both, all in one tick. A memo c = createMemo(() => m1() + m2()) that hadn't read them yet ends up with no value: latest(c) throws NotReadyError, and a Loading fallback over it stays up.

D-22 (RULES-DERIVED) says both answers are produced values: "whether the landing ran before the re-ask reached c is the flush's order". So latest(c) should read 2 + 11 = 13. Answering in its own tick first gives 13 (control case below).

const [s, setS] = createSignal(1);
const mk = (off: number) =>
  createMemo(() => {
    const v = off + s();
    return new Promise<number>(resolve => asks.push({ v, resolve }));
  });
const m1 = mk(1), m2 = mk(10);
const c = createMemo(() => m1() + m2());
createRoot(() => createRenderEffect(() => `${latest(c)}|${isPending(c)}`, () => {}));
flush(); await task(); flush();
for (const a of asks.splice(0)) a.resolve(a.v); // both answer...
setS(2);                                         // ...and are re-asked, same tick
await task(); flush();
latest(c); // throws; expected 13

Cause, as review traced it:

  • asyncWrite flushes synchronously after every landing (schedule(); flush(); in core/async.ts).
  • The first landing (m1) flushes, and that flush recomputes m2, which the write dirtied, before m2's own reaction runs.
  • m2's answer then arrives with _inFlight !== result and is dropped.
  • So whichever source resolves second loses its answer.

This isn't a regression: on next every variant throws, including the one-source case c = m1(). #4459 fixes the one-source case. The two-source case still fails on top of it.

Found in review of #4459.

Activity

  1. ryansolid commented on Oct 30, 2026

    @ryansolid
    MemberAuthor

    Fixed on next by #4499 (ef0aadd); it ships in the next RC.


    Generated by Claude Code

  2. added a commit that references this issue on Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions