Skip to content

fix(search): bulkPut hangs instead of rejecting when an IndexedDB write fails - #637

Open
ppcvote wants to merge 2 commits into
mitre-attack:developfrom
ppcvote:fix/bulkput-settle
Open

fix(search): bulkPut hangs instead of rejecting when an IndexedDB write fails#637
ppcvote wants to merge 2 commits into
mitre-attack:developfrom
ppcvote:fix/bulkput-settle

Conversation

@ppcvote

@ppcvote ppcvote commented Aug 23, 2026

Copy link
Copy Markdown

Description of what has changed

TableWrapper.bulkPut ran its work inside new Promise(async (resolve) => ...) with no reject, and the chunk write at indexed-db-wrapper.js:60 was unguarded. When Dexie rejects there (QuotaExceededError, DatabaseClosedError, an aborted transaction) the rejection settled the executor's own throwaway promise, so the promise returned to the caller never settled at all. It hung rather than rejected.

That matters because SearchService.initializeAsync awaits it on the cold-cache path, and index.js:162 then spins on while (!searchServiceIsLoaded) with the parsing spinner shown. The .catch already written for that path at index.js:139 could not run, because nothing ever rejected.

The fix takes reject and wraps the chunk loop in try/catch, following the shape already used in backupSearchIndex. Dropping async from the executor also clears no-async-promise-executor, which this repo's eslint config sets to error: one problem at line 26 before, none after.

Two tests added to the existing file. They race the call against a 1s sentinel so a hang is distinguishable from a rejection; a plain rejects assertion would just time out and read as a slow test. Both report Received: "HUNG" before the change and pass after. Full suite: 44 passing.

CHANGELOG.md has an Unreleased section for this. There was no pending heading, so please fold it into whichever version you cut next.

Issues addressed by pull request

None open that I could find; the failure is silent, so it would surface as "search never finishes loading" rather than an error.

@isaisabel for review, per the template.

TableWrapper.bulkPut ran its work inside an async Promise executor with no
reject, so a rejected chunk write settled the executor's own promise rather
than the returned one. The promise never settled at all. SearchService's
cold-cache path waits on it behind `while (!searchServiceIsLoaded)`, so the
parsing spinner stays up for good, and the .catch already written for that
path in index.js could not run because nothing ever rejected.

Signed-off-by: ppcvote <risky9763@gmail.com>
Signed-off-by: ppcvote <risky9763@gmail.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.

1 participant