Skip to content

affects on a keyed source (source xs key id = …) throws INVALID_AFFECTS_TARGET; the action never reaches its await #50

Open

Description

@revosw

Filed with Opus 5.5. I personally don't have the required understanding to know whether it's something worth fixing, but I had a stab at converting my web app to use reactivescript. Very excited for the development, so I'll continue to file (hopefully) useful issues, based on the migration efforts

Versions: @reactivescript/compiler + @reactivescript/runtime 0.1.0 (also main at 08255de), solid-js 2.0.0-rc.21 (also Solid next at bcef104).

Repro

import pure { load } from "./api"
import { save } from "./api"

export default component App() {
  source tick: number := 0
  day = await load(tick)
  source rows key id = day.rows
  source err: string := "none"
  action move(id: string, at: number) {
    try {
      let i = rows.findIndex(r => r.id == id)
      optimistic rows[i].at := at
      affects rows
      await save(id, at)
      refresh day
    } catch (e) { err := e.message }
  }
  errored fallback(e) { <p>error</p> } {
    loading fallback { <p>loading</p> } {
      <button onClick={() => { move("a", 5) }}>move</button>
      <p>{rows.map(r => `${r.id}@${r.at}`).join(",")} {err}</p>
    }
  }
}

Expected (AC-5): the guess shows, pending? rows is true until the action ends, and save is called.

Actual (dev build, browser): affects rows throws:

[INVALID_AFFECTS_TARGET] affects() expects a Solid source accessor or a store. Pass the store proxy (optionally with a property key) or the original accessor, not a wrapper function or an already-read value.

The catch receives it, save is never called, and the guess reverts. In a production build Solid's affects() returns without doing anything instead, so the save runs but pending? rows is never true.

Cause: source xs key id = … lowers to createOptimisticStore, and the runtime returns the accessor () => store (registered in storeAccs). affects passes that wrapper straight to Solid (ref/compile/rt-web.ts, the affects: line). refresh, one line above, already unwraps it: storeAccs.has(t) ? t() : t.

Suggested fix:

affects: (get: Acc) => affects((storeAccs.has(get) ? get() : get) as any),

No scenario currently uses affects on a keyed or structured source, so a scenario for this case would pin it.

Activity

  1. revosw commented on Nov 11, 2026

    @revosw
    Author

    Runnable repro with recordings of the bug and the fix, dev and production: https://github.com/revosw/reactivescript-affects-repro

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