{"record":{"id":"894acdb3eed0af4a","repo":"HeyPuter/puter","slug":"access-denied-894acd","errorCode":"access_denied","errorMessage":"Access denied","messagePattern":"Access denied","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/controllers/fs/legacyFsHelpers.ts","lineNumber":216,"sourceCode":"        typeof safe?.fields?.code === 'string' ? safe.fields.code : undefined;\n    const legacyCode = code === 'forbidden' ? 'access_denied' : code;\n\n    // App-under-user actors see denials as 404 \"subject_does_not_exist\"\n    // so existence of a sibling user's / other-app's files isn't leaked\n    // through the error code. User-actor denials keep the real 403.\n\n    if (isAppActor(actor)) {\n        throw new HttpError(404, `Entry not found: path=${path}`, {\n            legacyCode: 'subject_does_not_exist',\n        });\n    }\n\n    if (status === 404) {\n        throw new HttpError(404, message, {\n            ...(legacyCode ? { legacyCode } : {}),\n        });\n    }\n    throw new HttpError(403, message, {\n        legacyCode: legacyCode ?? 'access_denied',\n    });\n}\n\n/**\n * Authorize creation of a new entry at `targetPath`. The standard rule is write\n * on the parent, but we also allow it when the actor has explicit write on the\n * target itself — this covers an app creating its own\n * `/<user>/AppData/<app_uid>` folder (parent `AppData` is off-limits, but the\n * target is the app's own subtree per ACLService's short-circuit) and shares\n * granted directly on a not-yet-created path.\n *\n * On failure, delegates to `assertAccess` on the parent so the error shape\n * stays identical to the previous parent-only check.\n */\nexport async function assertCanCreate(\n    aclService: ACLService,\n    fsService: FSService,","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/fs/legacyFsHelpers.ts#L198-L234","documentation":"The default `assertAccess` failure for a user actor: the ACL check denied access (not a 404-from-ACL case) and the helper throws 403 with `legacyCode: 'access_denied'` (or the ACL layer's own code, with `forbidden` mapped to `access_denied`). This is the standard 'permission denied' for user-actor requests.","triggerScenarios":"A user reads/writes a path they don't own and that hasn't been shared with them; an attempt to write into another user's home or a read-only share.","commonSituations":"No share granted; share is read-only but the op needs write; user switched accounts and lost access; share expired or was revoked.","solutions":["Have the owner share the path with the user at the required mode (read or write).","Switch to the owning account if you own the resource.","Verify the share mode matches the operation (write ops need write share)."],"exampleFix":"// before — user lacks write on a shared folder\nawait puter.fs.write('/shared/doc.txt', content); // 403 access_denied\n\n// after — owner grants write, then retry\nawait owner.acl.grant({ subject: '/shared/doc.txt', user: userId, mode: 'write' });\nawait puter.fs.write('/shared/doc.txt', content);","handlingStrategy":"try-catch","validationCode":"async function canAccess(acl, actor, path, mode) { return await acl.check(actor, { path }, mode); }\nif (!await canAccess(acl, actor, path, 'write')) throw new Error('request write share first');","typeGuard":"function isAccessDenied(e) { return e?.status === 403 && e?.code === 'access_denied'; }","tryCatchPattern":"try { await fs.write(path, data); }\ncatch (e) { if (isAccessDenied(e)) { await requestShare(path, 'write'); return retry(); } throw e; }","preventionTips":["Request a share at the correct mode (read/write) before operating.","Switch to the owning account if you own the resource.","Re-verify share mode matches the operation before retry."],"tags":["acl","authz","forbidden","access-denied","v1-api"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}