{"record":{"id":"1b59d8597801e59b","repo":"mastra-ai/mastra","slug":"mount-requestedmount-is-read-only","errorCode":null,"errorMessage":"Mount \"${requestedMount}\" is read-only","messagePattern":"Mount \"(.+?)\" is read-only","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"packages/server/src/server/handlers/workspace.ts","lineNumber":215,"sourceCode":" * For non-composite: returns `.agents/skills/<skillId>` (unchanged behavior).\n */\n/** Strip a single trailing slash (leaves `/` alone). */\nfunction stripTrailingSlash(p: string): string {\n  return p.length > 1 && p.endsWith('/') ? p.slice(0, -1) : p;\n}\n\nfunction buildSkillInstallPath(filesystem: WorkspaceFilesystem, safeSkillId: string, requestedMount?: string): string {\n  if (isCompositeFilesystem(filesystem)) {\n    if (requestedMount) {\n      // Validate the requested mount exists\n      const mountFs = filesystem.mounts.get(requestedMount);\n      if (!mountFs) {\n        throw new HTTPException(400, {\n          message: `Mount \"${requestedMount}\" not found. Available mounts: ${filesystem.mountPaths.join(', ')}`,\n        });\n      }\n      if (mountFs.readOnly) {\n        throw new HTTPException(403, { message: `Mount \"${requestedMount}\" is read-only` });\n      }\n      return `${stripTrailingSlash(requestedMount)}/${SKILLS_SH_DIR}/${safeSkillId}`;\n    }\n\n    // Default: use first writable mount\n    for (const [mountPath, mountFs] of filesystem.mounts) {\n      if (!mountFs.readOnly) {\n        return `${stripTrailingSlash(mountPath)}/${SKILLS_SH_DIR}/${safeSkillId}`;\n      }\n    }\n\n    throw new HTTPException(403, { message: 'No writable mount available for skill installation' });\n  }\n\n  // Non-composite: standard path\n  return `${SKILLS_SH_DIR}/${safeSkillId}`;\n}\n","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/workspace.ts#L197-L233","documentation":"Thrown by buildSkillInstallPath when the requested mount exists in the CompositeFilesystem but is flagged readOnly. Skill installation writes files, so the server refuses with HTTP 403 rather than writing to a read-only mount. This is an intentional safety guard, not a transient failure.","triggerScenarios":"Calling the skill install/skillPath endpoints with a mount parameter that maps to a mount configured with readOnly: true in the CompositeFilesystem, or the mount's readOnly flag changed (e.g. after a safety-config update) while clients still target it.","commonSituations":"Deploying a workspace with mounts locked to read-only for production safety while CI pipelines still install skills to those mounts; sharing one workspace config where one team's mount is intentionally immutable.","solutions":["Retry against a writable mount from the workspace's mount list (omit the mount parameter to auto-select the first writable mount).","If the mount should be writable, set readOnly: false for that mount in the CompositeFilesystem configuration and redeploy.","If immutability is intended, change the install pipeline to a mount that is designated for skill writes."],"exampleFix":"new CompositeFilesystem({\n  mounts: {\n    '/workspace': createFileSystem({ readOnly: false }), // before: readOnly: true\n  },\n})","handlingStrategy":"validation","validationCode":"const mountInfo = await getWorkspaceMountInfo(workspaceId); // [{path, readOnly}]\nconst target = mountInfo.find(m => m.path === mount);\nif (target?.readOnly) {\n  throw new Error(`Mount \"${mount}\" is read-only; pick a writable mount`);\n}","typeGuard":"function isWritableMount(m: { path: string; readOnly: boolean } | undefined): m is { path: string; readOnly: false } {\n  return !!m && m.readOnly === false;\n}","tryCatchPattern":"try {\n  await installSkill({ workspaceId, skillId, mount });\n} catch (e) {\n  if (isHttpException(e, 403) && e.message.includes('is read-only')) {\n    return installSkill({ workspaceId, skillId }); // auto-select first writable mount\n  }\n  throw e;\n}","preventionTips":["Check the mount's readOnly flag before any write or install operation.","Designate one mount per workspace as the writable target for installs.","Treat 403 read-only errors as config issues, not retryable failures."],"tags":["workspace","filesystem","mount","read-only","forbidden"],"backgroundTag":"read-only-filesystem","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}