[@nuxt/content 3.16.1] `UNIQUE constraint failed: _development_cache.id` unhandled rejections: `insertDevelopmentCache` doesn't await the delete
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- node.js, sqlite, typescript
Research direction
Start by locating insertDevelopmentCache and deleteDevelopmentCache in the package source corresponding to dist/module.mjs around the reported line 361; trace their callers in the build loop and watcher. Reproduce with two builds after changing a Markdown file, then verify the delete completes before insertion and that callers handle the promise. Done when cache refreshes without unhandled rejections or missing rows.
Written by the indexing model from the issue text.
Description
Environment
- OS: Windows 11
- Node: 24.21.0
- Package manager: npm 11.19.0
- Framework: Nuxt 4.5.2
- Affected package: @nuxt/content 3.16.1 (same code in 3.15.2)
- db0: 0.4.1 (nested under @nuxt/content)
- better-sqlite3: 13.0.3 (local cache database)
Steps to reproduce
- Build a project with markdown collections once, so that
_development_cachegets populated:
npx nuxt build
- Change some markdown files (or upgrade @nuxt/content, so that the collection/config hash changes) and build again:
npx nuxt build
Describe the bug
When a cached entry exists but its checksum no longer matches, the build logs one UNIQUE constraint failed: _development_cache.id unhandled rejection per changed file. The build completes, but the cache rows for those files end up missing and they are parsed again on the next build, which then runs clean.
Root cause: insertDevelopmentCache calls deleteDevelopmentCache(id) without await, and deleteDevelopmentCache doesn't await its own run() either:
const insertDevelopmentCache = async (id, value, checksum) => {
deleteDevelopmentCache(id);
const insert = generateCollectionInsert(cacheCollection, { id, value, checksum });
for (const query of insert.queries) {
await db.exec(query);
}
};
const deleteDevelopmentCache = async (id) => {
db.prepare(`DELETE FROM _development_cache WHERE id = ?`).run(id);
};
With the db0 better-sqlite3 connector, prepare() returns a wrapper whose run() first awaits getDB() and then the prepared statement (two awaits), while exec() awaits getDB() only once. So the INSERT executes before the DELETE and hits the existing primary key. The callers (db.insertDevelopmentCache(...) in the build loop and in the watcher) don't await or catch it either, so the rejection is unhandled.
Suggested fix:
const insertDevelopmentCache = async (id, value, checksum) => {
await deleteDevelopmentCache(id);
// ...
};
const deleteDevelopmentCache = async (id) => {
await db.prepare(`DELETE FROM _development_cache WHERE id = ?`).run(id);
};
(or a single INSERT OR REPLACE).
Logs
ERROR [unhandledRejection] UNIQUE constraint failed: _development_cache.id
at Database.exec (node_modules\better-sqlite3\lib\methods\wrappers.js:9:14)
at Object.exec (/C:/projects/my-app/node_modules/@nuxt/content/node_modules/db0/dist/connectors/better-sqlite3.mjs:22:40)
at async Object.insertDevelopmentCache (/C:/projects/my-app/node_modules/@nuxt/content/dist/module.mjs:361:7)
Additional context
The error was printed 7 times in a single build (7 changed files) and disappeared on the following build. It doesn't break the output, but it is noisy and it silently drops the cache entries it was supposed to refresh. The same pattern is present in @nuxt/content 3.15.2.
- Dominant language
- TypeScript
- Stars
- 3.7k
- Forks
- 746
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 10
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from nuxt/content
-
defineGitSourceOpen
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
nuxt/content#3818 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
nuxt/content#3813 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
D1: content upgrades fail when more than 100 documents are removed or changed (too many SQL variables)Possibly taken @zizzfizzix claimed this 7 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Maintainers usually reply within 1 day
-
Cloudflare D1: Integrity check occasionally damages database without self-recoveryPossibly taken @zizzfizzix claimed this 7 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 38/100
nuxt/content#3854 · 1 comment ·
Maintainers usually reply within 1 day
Similar issues
-
area:workflow bug ready-for-human
Difficulty 1/5 Under an hour Newbie friendliness 78/100
fil-donadoni/tolaria#6108 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
apache/rocketmq-dashboard#7234 ·
Maintainers usually reply within 3 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
vitest-dev/vitest#11656 ·
Maintainers usually reply within 1 day
-
e2e-failure ready-to-code
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
redhat-developer/rhdh-plugin-export-overlays#4460 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
ehmpathy/rhachet-roles-bhrain#655 ·
Maintainers usually reply within 1 day