{"record":{"id":"f4ca154a9d31e2b1","repo":"mastra-ai/mastra","slug":"read-only","errorCode":"READ_ONLY","errorMessage":"Workspace is in read-only mode. Cannot perform: ${operation}","messagePattern":"Workspace is in read-only mode\\. Cannot perform: (.+?)","errorType":"exception","errorClass":"WorkspaceReadOnlyError","httpStatus":null,"severity":"error","filePath":"packages/core/src/workspace/filesystem/local-filesystem.ts","lineNumber":339,"sourceCode":"   * Uses the same resolution logic as internal file operations.\n   * Returns `undefined` if the path violates containment.\n   */\n  resolveAbsolutePath(inputPath: string): string | undefined {\n    try {\n      return this.resolvePath(inputPath);\n    } catch {\n      // PermissionError from containment check — path is not resolvable\n      return undefined;\n    }\n  }\n\n  private toRelativePath(absolutePath: string): string {\n    return nodePath.relative(this._basePath, absolutePath).replace(/\\\\/g, '/');\n  }\n\n  private assertWritable(operation: string): void {\n    if (this.readOnly) {\n      throw new WorkspaceReadOnlyError(operation);\n    }\n  }\n\n  /**\n   * Verify that the resolved path doesn't escape basePath via symlinks.\n   * Uses realpath to resolve symlinks and check the actual target.\n   */\n  private async assertPathContained(absolutePath: string): Promise<void> {\n    if (!this._contained) return;\n\n    if (this._allowedPaths.some(root => this._isWithinRoot(absolutePath, root))) {\n      return;\n    }\n\n    // Resolve symlinks for the target path. If it doesn't exist,\n    // there are no symlinks to escape through — nothing to check.\n    let targetReal: string;\n    try {","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workspace/filesystem/local-filesystem.ts#L321-L357","documentation":"LocalFilesystem throws WorkspaceReadOnlyError (code READ_ONLY) when any mutating filesystem operation is attempted while the provider was constructed with readOnly: true. It is raised in assertWritable(), which every write path (writeFile, appendFile, deleteFile, copyFile, moveFile, mkdir) calls before touching disk. The error guards a deliberate configuration choice, not a runtime fault, so no data was modified.","triggerScenarios":"Calling writeFile, appendFile, deleteFile, copyFile, moveFile, or mkdir on a LocalFilesystem created with { readOnly: true } (or a Workspace configured with a read-only filesystem/mount); agent tools that write to files when the workspace policy is read-only.","commonSituations":"Serving a workspace as read-only reference material (docs, skills) while an agent attempts to save output; forgetting readOnly was enabled after switching an environment to production-safe defaults; a mounted sub-filesystem is read-only while the caller expects writes to land there.","solutions":["Remove readOnly: true from the LocalFilesystem options (or use a separate writable workspace) if writes are intended.","Check workspace.filesystem.info / isReadOnly before issuing write calls and route writes to a writable provider.","Catch WorkspaceReadOnlyError in the agent/tool layer and surface a clear message telling the model the workspace cannot be written.","If only some mounts are read-only, target the write to a mounted filesystem that is writable."],"exampleFix":"// before\nconst ws = new Workspace({ filesystem: new LocalFilesystem({ basePath: './data', readOnly: true }) });\nawait ws.writeFile('out.txt', 'hi'); // throws WorkspaceReadOnlyError\n// after\nconst ws = new Workspace({ filesystem: new LocalFilesystem({ basePath: './data' }) });\nawait ws.writeFile('out.txt', 'hi');","handlingStrategy":"try-catch","validationCode":"import { LocalFilesystem } from '@mastra/core/workspace';\nif (fsProvider.info?.readOnly) {\n  throw new Error('Workspace filesystem is read-only; writes are not permitted');\n}","typeGuard":"import { WorkspaceReadOnlyError } from '@mastra/core/workspace/errors';\nfunction isReadOnlyError(e: unknown): e is WorkspaceReadOnlyError {\n  return e instanceof WorkspaceReadOnlyError ||\n    (e instanceof Error && 'code' in e && (e as { code?: string }).code === 'READ_ONLY');\n}","tryCatchPattern":"try {\n  await ws.writeFile('out.txt', data);\n} catch (e) {\n  if (isReadOnlyError(e)) {\n    logger.warn('Workspace is read-only; skipping write');\n    return;\n  }\n  throw e;\n}","preventionTips":["Check the provider's readOnly flag at startup and configure write tools only for writable workspaces.","Give agents a separate scratch workspace for writes and keep reference data read-only.","Include readOnly status in tool descriptions so the model doesn't attempt writes.","Centralize writes behind a helper that checks writability once instead of scattering raw calls."],"tags":["filesystem","read-only","workspace","configuration"],"backgroundTag":"filesystem-read-only","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}