{"record":{"id":"ee66d72e4b3f00d2","repo":"HeyPuter/puter","slug":"permission-denied-ee66d7","errorCode":"permission_denied","errorMessage":"Permission denied","messagePattern":"Permission denied","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/controllers/webdav/WebDAVController.ts","lineNumber":845,"sourceCode":"        if (lock.path !== davPath)\n            throw new HttpError(403, 'Lock token does not match this path', {\n                legacyCode: 'forbidden',\n            });\n\n        await deleteLock(r, token);\n        res.status(204).end();\n    }\n\n    // -- ACL helpers -------------------------------------------------\n\n    async #assertRead(actor: Actor, path: string): Promise<void> {\n        const descriptor = {\n            path,\n            resolveAncestors: () => this.services.fs.getAncestorChain(path),\n        };\n        const ok = await this.services.acl.check(actor, descriptor, 'read');\n        if (!ok)\n            throw new HttpError(403, 'Permission denied', {\n                legacyCode: 'permission_denied',\n            });\n    }\n\n    async #assertWrite(actor: Actor, path: string): Promise<void> {\n        const descriptor = {\n            path,\n            resolveAncestors: () => this.services.fs.getAncestorChain(path),\n        };\n        const ok = await this.services.acl.check(actor, descriptor, 'write');\n        if (!ok)\n            throw new HttpError(403, 'Permission denied', {\n                legacyCode: 'permission_denied',\n            });\n    }\n\n    // -- Event emission ----------------------------------------------\n","sourceCodeStart":827,"sourceCodeEnd":863,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/webdav/WebDAVController.ts#L827-L863","documentation":"Thrown by the WebDAV #assertRead helper when ACLService.check(actor, descriptor, 'read') returns false — the authenticated actor lacks read permission on the path (or its nearest resolvable ancestor). Returns 403 Forbidden. Read is required for GET, HEAD, PROPFIND, and the source side of COPY.","triggerScenarios":"A GET/HEAD/PROPFIND/COPY-source request on a dav.* path whose ACL does not grant the actor's user the read permission. The descriptor resolves ancestors via FSService.getAncestorChain, so denial on any ancestor in the chain triggers it.","commonSituations":"Accessing another user's shared file without a granted permission; permission revoked between sessions; path under a directory whose ACL was tightened; wrong account authenticated (basic-auth credentials for a different user); newly created entry whose ACL seed omitted the user.","solutions":["Authenticate as a user who has been granted read on the path or a parent.","Grant read permission on the path (or a parent) to the actor via the Puter sharing/ACL API.","Verify the basic-auth credentials being sent correspond to the intended user account.","Check the ACL entries on each ancestor up to root to locate where permission is denied."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-check read permission via the Puter ACL/sharing API before the DAV call\nconst allowed = await puter.fs.stat(path).then(() => true).catch(() => false);\nif (!allowed) throw new Error(`No read access to ${path}`);","typeGuard":null,"tryCatchPattern":"try {\n  await webdavGet(path);\n} catch (e) {\n  if (e.status === 403) console.error(`Read denied on ${path} — request sharing grant`);\n  else throw e;\n}","preventionTips":["Authenticate with credentials for a user who has read access on the path.","Grant read permission on the path or a parent before accessing it over DAV.","Confirm basic-auth credentials match the intended user account.","Walk the ACL chain on the path and ancestors to find where read is denied."],"tags":["webdav","http","acl","permission","forbidden","read"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}