mastra-ai/mastra · error · WorkspaceReadOnlyError

READ_ONLY

READ_ONLY

Error message

Workspace is in read-only mode. Cannot perform: write_file

What it means

The `writeFile` tool refuses to write when the workspace filesystem is read-only. Before calling `filesystem.writeFile`, it checks `filesystem.readOnly` and throws `WorkspaceReadOnlyError('write_file')`. This protects read-only mounted workspaces from any mutation via agent tools.

Source

Thrown at packages/core/src/workspace/tools/write-file.ts:30

  inputSchema: z.object({
    path: z.string().describe('The path where to write the file (e.g., "data/output.txt")'),
    content: z.string().describe('The content to write to the file'),
    overwrite: z.boolean().optional().default(true).describe('Whether to overwrite the file if it already exists'),
  }),
  execute: async ({ path, content, overwrite }, context) => {
    const { workspace, filesystem } = requireFilesystem(context);
    await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE);

    const span = startWorkspaceSpan(context, workspace, {
      category: 'filesystem',
      operation: 'writeFile',
      input: { path, overwrite, contentLength: content.length },
      attributes: { filesystemProvider: filesystem.provider },
    });

    try {
      if (filesystem.readOnly) {
        throw new WorkspaceReadOnlyError('write_file');
      }

      await filesystem.writeFile(path, content, {
        overwrite,
        expectedMtime: (context as any)?.__expectedMtime,
      });

      const size = Buffer.byteLength(content, 'utf-8');
      let output = `Wrote ${size} bytes to ${path}`;
      output += await getEditDiagnosticsText(workspace, path, content);
      span.end({ success: true }, { bytesTransferred: size });
      return output;
    } catch (err) {
      span.error(err);
      throw err;
    }
  },
});

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Construct the filesystem with read-only disabled if writes are intended
  2. Remove write_file (and other mutators) from the tools config for read-only workspaces
  3. Persist intended changes elsewhere (e.g. output a patch) and apply them outside the read-only workspace

Example fix

// before
new LocalFilesystem('/mnt/readonly', { readOnly: true }) // write_file tool enabled

// after
new LocalFilesystem('/mnt/readonly', { readOnly: true })
// tools: only read tools enabled for this workspace
Defensive patterns

Strategy: validation

Validate before calling

if (filesystem.readOnly) {
  throw new Error('write_file cannot be used on a read-only workspace.');
}

Try / catch

try {
  await writeFileTool.execute({ path, content }, ctx);
} catch (err) {
  if (err?.code === 'READ_ONLY') {
    return { error: 'Workspace is read-only; produce a diff/patch instead.' };
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling the `write_file` workspace tool while `filesystem.readOnly === true`, including with `overwrite: true` — the check happens before any write attempt.

Common situations: Agents attached to a read-only snapshot or prod mount; the `expectedMtime` concurrency mechanism irrelevant because writes are disallowed entirely; forgetting to disable write tools on read-only workspaces.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/9c4358e1e499e358. Report an issue: GitHub.