Skip to content

Fix vitest watch with durable objects#11771

Merged
petebacondarwin merged 9 commits intomainfrom
fix-vitest-watch
Feb 10, 2026
Merged

Fix vitest watch with durable objects#11771
petebacondarwin merged 9 commits intomainfrom
fix-vitest-watch

Conversation

@avenceslau
Copy link
Contributor

@avenceslau avenceslau commented Dec 30, 2025

Fixes #9913
Fixes #10506

Running vitest-pool-workers with vitest --watch would fail second runs due to SQLITE_CANT_OPEN errors or internal reference errors. This was a bug in one of the functions that handles clean up between tests emptyDir, for DOs specifically we were deleting not only the sqlite files but also the dir itself.

This meant that workerd would not be able to recreate the DO's sqlite storage and DOs would fail to reboot up.

  • Tests
    • Tests included/updated
    • Tests not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: Just a bug fix

A picture of a cute animal (not mandatory, but encouraged)


Open with Devin

@changeset-bot
Copy link

changeset-bot bot commented Dec 30, 2025

🦋 Changeset detected

Latest commit: 1ee29ce

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@claude
Copy link
Contributor

claude bot commented Dec 30, 2025

Claude finished @avenceslau's task —— View job


Changeset Review

All changesets look good

The changeset .changeset/fix-do-storage-reset.md is well-formatted and appropriate:

  1. Version Type: ✅ Correctly uses patch for a bug fix
  2. Changelog Quality: ✅ Clear title and detailed explanation of the issue and solution
  3. Markdown Headers: ✅ No h1/h2/h3 headers used
  4. Package: ✅ Correctly targets @cloudflare/vitest-pool-workers
  5. Description: ✅ Explains both the symptom (SQLITE_CANTOPEN errors) and the root cause (directory deletion breaking workerd file handles)

The changeset provides excellent context about what was broken, why it was broken, and how it was fixed. This will create a useful changelog entry for users experiencing this issue.


@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 30, 2025

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@11771

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@11771

miniflare

npm i https://pkg.pr.new/miniflare@11771

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@11771

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@11771

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@11771

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@11771

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@11771

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@11771

wrangler

npm i https://pkg.pr.new/wrangler@11771

commit: 1ee29ce

@avenceslau avenceslau marked this pull request as ready for review January 2, 2026 11:08
@avenceslau avenceslau requested a review from a team as a code owner January 2, 2026 11:08
@petebacondarwin
Copy link
Contributor

@claude

@claude
Copy link
Contributor

claude bot commented Jan 3, 2026

Claude finished @petebacondarwin's task —— View job


PR Review: Fix vitest watch with durable objects

Todo List:

  • Review implementation changes in loopback.ts
  • Review new test file watch.test.ts
  • Review changeset for correctness
  • Provide comprehensive feedback

✅ Excellent Fix!

This PR correctly resolves the issue where vitest watch mode would fail on second runs with SQLITE_CANTOPEN errors. The problem and solution are well-understood and properly implemented.

Key Changes Analysis

Main Fix in packages/vitest-pool-workers/src/pool/loopback.ts:64-93:

The emptyDir function was modified to preserve directory structure while cleaning files:

  • Before: Used fs.rm(path, { recursive: true, force: true }) which deleted entire directories
  • After: Recursively empties directories but preserves the directory structure itself

This is crucial because workerd holds file handles to SQLite database directories, and deleting the directories entirely would invalidate those handles.

Specific improvements:

  1. Detailed file type checking: Uses fs.readdir(dirPath, { withFileTypes: true }) to distinguish files from directories
  2. Recursive emptying: Directories are recursively emptied via await emptyDir(fullPath) instead of being deleted
  3. File-only deletion: Only files are deleted with fs.rm(fullPath, { force: true })
  4. Better error handling: Improved error message specificity ("Unable to remove file" vs "Unable to remove temporary directory")

Test Coverage

Comprehensive test suite in packages/vitest-pool-workers/test/watch.test.ts:

The tests cover all the critical scenarios:

  • ✅ Storage reset between runs (isolated & shared storage)
  • Watch mode functionality (the core issue being fixed)
  • ✅ Automatic re-runs for unit and integration tests
  • ✅ Module graph reset in watch mode

The watch mode tests specifically verify that:

  • Tests pass on initial run
  • Tests continue to pass on subsequent runs after file changes
  • Both isolatedStorage: true and false configurations work correctly

Changeset Review

.changeset/fix-do-storage-reset.md:

  • ✅ Appropriate patch version bump for a bug fix
  • ✅ Clear, descriptive changelog entry explaining the root cause
  • ✅ Technical details about the solution (preserving directories vs deleting them)

Code Quality

  • Maintains backward compatibility: No API changes
  • Follows existing patterns: Consistent with codebase error handling style
  • Proper error handling: Preserves existing EBUSY error handling with improved messaging
  • Well-documented: The change aligns with the extensive comments explaining the stacked storage system

Security & Performance

  • No security concerns: File operations are contained within the expected persistence directories
  • Performance neutral/positive: Recursive directory traversal vs rm -rf should have similar performance, potentially faster for subsequent runs since directory creation is avoided

Overall Assessment

This is a high-quality fix that:

  1. Correctly identifies the root cause: Directory deletion invalidating workerd file handles
  2. Implements a targeted solution: Preserve directories, remove only files
  3. Includes comprehensive tests: Validates the fix works in watch mode scenarios
  4. Maintains code quality: Follows existing patterns and error handling

Recommendation: ✅ Approve and merge

This fix resolves a significant usability issue with vitest watch mode for Durable Objects without introducing any risks or breaking changes.


Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

@github-project-automation github-project-automation bot moved this from Untriaged to Approved in workers-sdk Feb 10, 2026
@petebacondarwin petebacondarwin merged commit 4b6fd36 into main Feb 10, 2026
40 of 41 checks passed
@petebacondarwin petebacondarwin deleted the fix-vitest-watch branch February 10, 2026 18:42
@github-project-automation github-project-automation bot moved this from Approved to Done in workers-sdk Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

3 participants