vitest-dev/vitest · warning · Error

Test file "${id}" was not registered, so it cannot be update

Error message

Test file "${id}" was not registered, so it cannot be updated using the API.

What it means

Thrown by the saveTestFile RPC handler in packages/vitest/src/api/setup.ts when the WebSocket API client (typically the Vitest UI or an editor integration) requests a saveTestFile for an id that is neither in ctx.state.filesMap nor present on disk. The save is refused to avoid creating phantom files or overwriting unrelated paths through the API surface.

Source

Thrown at packages/vitest/src/api/setup.ts:76

  function setupClient(ws: WebSocket) {
    const rpc = createBirpc<WebSocketEvents, WebSocketHandlers>(
      {
        getFiles() {
          return ctx.state.getFiles()
        },
        getPaths() {
          return ctx.state.getPaths()
        },
        async readTestFile(id) {
          if (!ctx.state.filesMap.has(id) || !existsSync(id)) {
            return null
          }
          return fs.readFile(id, 'utf-8')
        },
        async saveTestFile(id, content) {
          if (!ctx.state.filesMap.has(id) || !existsSync(id)) {
            throw new Error(
              `Test file "${id}" was not registered, so it cannot be updated using the API.`,
            )
          }
          // silently ignore write attempts if not allowed
          if (!ctx.config.api.allowWrite) {
            return
          }
          return fs.writeFile(id, content, 'utf-8')
        },
        async rerun(files, resetTestNamePattern) {
          // silently ignore exec attempts if not allowed
          if (!ctx.config.api.allowExec) {
            return
          }
          await ctx.rerunFiles(files, undefined, true, resetTestNamePattern)
        },
        async rerunTask(id) {
          // silently ignore exec attempts if not allowed

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Save the file once on disk first, then trigger a Vitest re-run/re-collection so filesMap picks it up.
  2. Ensure the file matches test.include and lives under the project root Vitest was started with.
  3. If using the UI, refresh the file list so the new spec is collected before editing through the API.
  4. Confirm the WebSocket client is talking to the same Vitest instance that collected the tests (no stale reconnect).
Defensive patterns

Strategy: validation

Validate before calling

function isRegisteredTestFile(id: string, filesMap: Map<string, unknown>): boolean {
  return filesMap.has(id)
}

Try / catch

try {
  await rpc.saveTestFile(id, content)
} catch (err) {
  if (err.message.includes('was not registered')) {
    // trigger re-collection then retry
  } else throw err
}

Prevention

When it happens

Trigger: The UI sends a save request for a file that hasn't been collected in this run (e.g. a newly created test file not yet picked up by the watcher); the file was deleted between collection and the save request; an external tool calling the RPC with a stale id.

Common situations: Editor saves a brand-new test file before Vitest re-collects; watcher missed an add event; race between file creation, save, and glob re-scan; the API is being driven against a Vitest server that doesn't have that file in its project root.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/099fd92676e66cd9.json. Report an issue: GitHub.