Skip to content

fix(core): native embeddings load failure is cached forever — one failed first load bricks the backend until restart #1567

Closed

Description

@dezren39

Summary

The native in-process embeddings backend (#1559, step 2 of #1554) caches the model-load promise forever — including when the load fails. One failed first load permanently bricks the native backend for the life of the server process, and every later call replays the original error even after the underlying problem is fixed on disk.

Evidence

packages/core/src/embeddings-native.ts:94-128 (origin/main 3bd4efaaf8):

const loadedModels = new Map<string, Promise<LoadedModel>>()

const loadModel = (snapshotDir: string, onnxFile: string): Promise<LoadedModel> => {
  const key = `${snapshotDir}\n${onnxFile}`
  const existing = loadedModels.get(key)
  if (existing) return existing
  const pending = (async (): Promise<LoadedModel> => { ... })()
  loadedModels.set(key, pending)
  return pending
}

The rejected promise is never evicted, so a transient first-load failure (snapshot still syncing, tokenizer.json not yet written, a briefly-missing graph file) is final.

Reproduced this run on the laptop against a clean git archive of origin/main, driving embedNative directly with a temp snapshot dir (no model artifact needed — both failures occur before any native binding loads):

call1 (empty snapshot dir)
  => native-onnx embeddings backend: no tokenizer.json in model snapshot /tmp/embed-snap-XXXXXX
# tokenizer.json then created in that same directory; graph still missing
call2 (tokenizer.json now present, graph still missing)
  => native-onnx embeddings backend: no tokenizer.json in model snapshot /tmp/embed-snap-XXXXXX   ← stale cached error

Expected call2 behavior: the load is retried and fails at the next real problem — no ONNX graph at <dir>/onnx/model_int8.onnx — or succeeds once the snapshot is complete.

Why it matters

Step 3 of #1554 flips a registration to native-onnx deliberately. The first embed call after that flip is exactly when a snapshot problem is most likely (wrong path, partial HF download). Today that first failure is unrecoverable without a server restart, and the error message actively misleads: it names a file that may already exist by the time anyone reads the log. The HTTP sidecar this replaces has no equivalent failure mode — a fixed sidecar serves the very next request.

Acceptance criteria

  • A failed load is evicted from loadedModels (only if the map still holds that same promise), so the next embedNative call retries the load from disk.
  • A successful load stays cached and shared exactly as today (one load per (snapshot, graph) pair; concurrent first calls still share one load).
  • Regression test that needs no model artifact and no native bindings: first call against a snapshot dir missing tokenizer.json fails with the tokenizer error; after tokenizer.json is created in that dir, a second call fails with the graph error (proving the retry reached the next check) instead of replaying the tokenizer error. packages/core/test/embeddings-native.test.ts is the natural home — outside the snapshot-gated parity describe, since CI has no model file.
  • Existing embeddings suites stay green: packages/core/test/embeddings-native.test.ts, packages/core/test/embeddings.test.ts.

Part of the #1554 native-embeddings series; found by the new-issue-creator sweep while verifying #1559 on main.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    kind/testTest coverage, test infrastructure, or test-only fixes
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/corePackage: core (pkgs/ or apps/ in this repo)
    effort/xsTrivial: expected under 30 minutes of work
    on Nov 3, 2026
  2. dezren39 commented on Nov 3, 2026

    @dezren39
    Author

    🤖 Agent note · state: filed

    • Agent: new-issue-creator job (new-issue-creator-opencode)
    • Session / ID: cron new-issue-creator-opencode, run 2026-11-03 15:35 CST
    • Found via: filed this run
    • Task: Filed this issue — the native embeddings backend's loadedModels cache (packages/core/src/embeddings-native.ts:94-128) stores the load promise before it settles and never evicts a rejection, so one failed first load bricks the backend for the process lifetime and replays the stale error. Verified on a clean laptop archive probe of origin/main 3bd4efa by driving embedNative against a temp snapshot dir: call 1 (no tokenizer.json) failed with the tokenizer error; after tokenizer.json was created in that dir, call 2 returned the same tokenizer error instead of advancing to the missing-graph error.
    • Expectation: effort xs — evict a rejected load from loadedModels so the next call retries from disk (successful loads stay cached/shared), plus a model-free regression test in packages/core/test/embeddings-native.test.ts proving the retry reaches the next check; done when that test and the existing embeddings suites pass.
    • Links: queue packet enqueued to repo-health-opencode-pilot this run
  3. added
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  4. 4 remaining items

  5. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    🤖 Agent note · picked up

  6. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    🤖 Agent note · parked

  7. added
    status/parkedDeliberately paused with a recorded resume condition
    and removed on Nov 4, 2026
  8. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    🤖 Agent note · picked up

  9. dezren39 commented on Nov 4, 2026

    @dezren39
    Author

    🤖 Agent note · parked

  10. added
    queue/claimedA queue worker has claimed the task for this item
    user/escalatedMuse reviewed it; the decision is genuinely the user's — escalated with Muse's read attached
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 5, 2026
  11. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · picked up

  12. dezren39 commented on Nov 5, 2026

    @dezren39
    Author

    🤖 Agent note · escalated

  13. added a commit that references this issue on Nov 5, 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

    app/corePackage: core (pkgs/ or apps/ in this repo)effort/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)kind/testTest coverage, test infrastructure, or test-only fixespriority/normalOrdinary priority (the default)queue/claimedA queue worker has claimed the task for this itemsource/creatorFiled by the new-issue-creator jobstatus/in-progressActively being workedtask/small-fixQueue packet kind: bounded fix with reproduction and targeted testsuser/escalatedMuse reviewed it; the decision is genuinely the user's — escalated with Muse's read attachedwork/assignedAn agent holds this item via the queue (claimed task)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions