{"record":{"id":"41d9a25ce905f048","repo":"HeyPuter/puter","slug":"access-denied-41d9a2","errorCode":"access_denied","errorMessage":"Write access denied for destination","messagePattern":"Write access denied for destination","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/drivers/ai-image/ImageGenerationDriver.ts","lineNumber":477,"sourceCode":"        let ancestorsCache: Promise<\n            Array<{ uid: string; path: string }>\n        > | null = null;\n        const canWrite = await this.services.acl.check(\n            actor,\n            {\n                path: pathToCheck,\n                resolveAncestors() {\n                    if (!ancestorsCache) {\n                        ancestorsCache =\n                            fsService.getAncestorChain(pathToCheck);\n                    }\n                    return ancestorsCache;\n                },\n            },\n            'write',\n        );\n        if (!canWrite) {\n            throw new HttpError(403, 'Write access denied for destination', {\n                legacyCode: 'access_denied',\n            });\n        }\n    }\n\n    #resolveModel(modelId: string, provider?: string): IImageModel | null {\n        const models = this.#modelIdMap[modelId];\n        if (!models || models.length === 0) return null;\n        if (!provider) return models[0];\n        return models.find((m) => m.provider === provider) ?? models[0];\n    }\n}\n","sourceCodeStart":459,"sourceCodeEnd":490,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/ImageGenerationDriver.ts#L459-L490","documentation":"#assertWriteAccess runs an ACL check (this.services.acl.check with 'write') against the parent directory of the output path, resolving ancestors via fsService.getAncestorChain. If the actor lacks write permission on that directory, generate() throws HTTP 403 access_denied before spending credits. This enforces per-user filesystem permissions on generated-image output.","triggerScenarios":"The authenticated user does not have write permission on the directory named by puter_output_path — another user's folder, a read-only/app directory, or a path the user can't reach.","commonSituations":"Trying to save generated images into someone else's dir, a shared/readonly folder, or a path that doesn't exist and isn't creatable under the user's space.","solutions":["Write into a directory the actor owns or has been granted write access to.","Pre-check the destination with the ACL/fs layer before calling generate().","Omit puter_output_path and handle the returned URL yourself if you don't need FS persistence."],"exampleFix":"// before\nawait driver.generate({ prompt, puter_output_path: '/someone-else/x.png' });\n// after\nawait driver.generate({ prompt, puter_output_path: `/${actor.user.username}/Pictures/x.png` });","handlingStrategy":"validation","validationCode":"// Pre-check write permission on the destination parent before generating.\nconst parent = posix.dirname(posix.normalize(puter_outputPath));\nconst ok = await aclService.check(actor, { path: parent }, 'write');\nif (!ok) throw new Error(`no write access to ${parent}`);","typeGuard":null,"tryCatchPattern":"try {\n  await driver.generate({ prompt, puter_output_path });\n} catch (e) {\n  if (e?.code === 'access_denied') { promptChooseWritableFolder(); return; }\n  throw e;\n}","preventionTips":["Write only into directories the actor owns or is granted write access to.","Pre-check the destination ACL before calling generate().","Default output paths to the user's own home folder."],"tags":["ai-image","acl","permissions","filesystem","access-denied"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}