mastra-ai/mastra · error · HTTPException
Workspace is read-only
Error message
Workspace is read-only
What it means
HTTPException 403 thrown when the target workspace's filesystem is marked readOnly. Installing skill files requires write access, so the handler rejects the request even though the workspace and its filesystem exist.
Source
Thrown at packages/server/src/server/handlers/workspace.ts:1434
responseSchema: skillsShInstallResponseSchema,
summary: 'Install skill from Skills API',
description: 'Installs a skill by fetching files from the Skills API and writing to workspace filesystem.',
tags: ['Workspace', 'Skills'],
handler: async ({ mastra, workspaceId, owner, repo, skillName, mount }) => {
try {
requireWorkspaceV1Support();
const workspace = await getWorkspaceById(mastra, workspaceId);
if (!workspace) {
throw new HTTPException(404, { message: 'Workspace not found' });
}
if (!workspace.filesystem) {
throw new HTTPException(400, { message: 'Workspace filesystem not available' });
}
if (workspace.filesystem.readOnly) {
throw new HTTPException(403, { message: 'Workspace is read-only' });
}
// Fetch skill files from the Skills API
const result = await fetchSkillFiles(owner, repo, skillName);
if (!result || result.files.length === 0) {
throw new HTTPException(404, {
message: `Could not find skill "${skillName}" in ${owner}/${repo}.`,
});
}
// Validate skill name to prevent path traversal
const safeSkillId = assertSafeSkillName(result.skillId);
const installPath = buildSkillInstallPath(workspace.filesystem, safeSkillId, mount);
// Ensure the skills directory exists
try {
await workspace.filesystem.mkdir(installPath, { recursive: true });
} catch {View on GitHub (pinned to 75dd419e61)
Solutions
- Use a writable workspace for skill installation.
- Change the workspace's readOnly flag / mount it read-write if policy allows, then retry.
- Write the skill files through an admin or privileged flow that has write access to the underlying storage.
Example fix
// before
await installSkill({ workspaceId: roWorkspaceId, ... }); // 403
// after
const ws = await getWorkspace(writableId); // filesystem.readOnly === false
await installSkill({ workspaceId: ws.id, ... }); Defensive patterns
Strategy: validation
Validate before calling
const ws = await getWorkspace(workspaceId);
if (ws?.filesystem?.readOnly) throw new Error('Workspace is read-only; select a writable workspace before installing skills.'); Type guard
function isWritableWorkspace(ws: unknown): boolean {
const f = (ws as any)?.filesystem;
return !!f && f.readOnly === false;
} Try / catch
try {
await installSkill({ workspaceId, ... });
} catch (e) {
if (/Workspace is read-only/.test(String(e))) {
throw new Error('Switch to a writable workspace or unlock this one before installing skills.');
}
throw e;
} Prevention
- Check filesystem.readOnly in the UI and disable install actions for read-only workspaces.
- Mount workspaces read-write when they are intended for skill installation.
- Re-check readOnly status after permission changes or workspace re-provisioning.
When it happens
Trigger: Calling the install-skill endpoint on a workspace whose filesystem.readOnly flag is true (e.g. snapshot/checked-out read-only checkouts, restricted environments).
Common situations: Workspaces mounted from read-only sources (git checkout, container image layers); intentionally locked workspaces during review; permission changes by an administrator after workspace creation.
Related errors
- Workspace is in read-only mode
- EACCES
- READ_ONLY
- Mount "${requestedMount}" is read-only
- Attaching a database requires the admin role in your organiz
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/03a649b42447fda6.
Report an issue: GitHub.