{"id":"6ea467508a0c2996","repo":"vitest-dev/vitest","slug":"cannot-modify-file-path-file-writing-is-disa","errorCode":null,"errorMessage":"Cannot modify file \"${path}\". File writing is disabled because the server is exposed to the internet, see https://vitest.dev/config/browser/api.","messagePattern":"Cannot modify file \"(.+?)\"\\. File writing is disabled because the server is exposed to the internet, see https://vitest\\.dev/config/browser/api\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/node/utils.ts","lineNumber":114,"sourceCode":"export function slash(path: string): string {\n  return path.replace(/\\\\/g, '/').replace(/\\/+/g, '/')\n}\n\nexport function assertBrowserFileAccess(project: TestProject, path: string): void {\n  const normalized = slash(path)\n  if (\n    !isFileLoadingAllowed(project.vite.config, normalized)\n    && !isFileLoadingAllowed(project.vitest.vite.config, normalized)\n  ) {\n    throw new Error(\n      `Access denied to \"${path}\". See Vite config documentation for \"server.fs\": https://vitejs.dev/config/server-options.html#server-fs-strict.`,\n    )\n  }\n}\n\nexport function assertBrowserApiWrite(project: TestProject, path: string): void {\n  if (!project.config.api.allowWrite || !project.vitest.config.api.allowWrite) {\n    throw new Error(\n      `Cannot modify file \"${path}\". File writing is disabled because the server is exposed to the internet, see https://vitest.dev/config/browser/api.`,\n    )\n  }\n}\n","sourceCodeStart":96,"sourceCodeEnd":119,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/node/utils.ts#L96-L119","documentation":"Thrown by assertBrowserApiWrite() when api.allowWrite is false on either the project config or the global Vitest config. Because the browser API server can be exposed to the network, file-writing browser commands (writeFile, removeFile, screenshots) are gated behind an explicit opt-in to prevent untrusted clients from mutating the host filesystem.","triggerScenarios":"Calling writeFile/removeFile (or a screenshot matcher that writes) from the browser while api.allowWrite is falsy. The check fires before any disk operation.","commonSituations":"Enabling the browser api host for remote/CI access but forgetting to set api.allowWrite=true; using page.writeFile() in tests without enabling the write permission; defaulting to a network-exposed api where allowWrite is intentionally off for safety.","solutions":["Set test.api.allowWrite = true in your config if you trust the clients (e.g. local dev).","Avoid file-writing browser commands; read needed data through the test runner instead.","If exposing the api publicly, keep allowWrite false and use a separate, authenticated upload path."],"exampleFix":"// before\nexport default defineConfig({\n  test: {\n    browser: { enabled: true, api: { port: 3000 } }, // allowWrite defaults false\n  },\n})\n// after\nexport default defineConfig({\n  test: {\n    browser: { enabled: true, api: { port: 3000, allowWrite: true } },\n  },\n})","handlingStrategy":"validation","validationCode":"function canWrite(project: { config: { api: { allowWrite?: boolean } } }): boolean {\n  return project.config.api.allowWrite === true\n}\nif (!canWrite(project)) {\n  throw new Error('Enable test.api.allowWrite to use writeFile/removeFile in browser')\n}","typeGuard":null,"tryCatchPattern":"try {\n  await writeFile(path, data)\n} catch (e) {\n  if (/File writing is disabled/i.test(String((e as Error).message))) {\n    // fall back to reading data through the runner instead\n  } else throw e\n}","preventionTips":["Set api.allowWrite only in trusted/local environments; keep it false when exposed publicly.","Prefer read-only browser interactions; do writes in the Node test runner via commands.","Document the security trade-off when enabling allowWrite for remote api access."],"tags":["browser-mode","filesystem","security","api","config"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}