{"record":{"id":"bf45519f9a927b82","repo":"HeyPuter/puter","slug":"missing-app-uuid","errorCode":null,"errorMessage":"Missing `app_uuid`","messagePattern":"Missing `app_uuid`","errorType":"http","errorClass":"HttpError","httpStatus":400,"severity":"error","filePath":"extensions/appTelemetry.ts","lineNumber":109,"sourceCode":"                [DEFAULT_FREE_SUBSCRIPTION]: 2,\n                [DEFAULT_TEMP_SUBSCRIPTION]: 2,\n            },\n        },\n    };\n\n    /** Users who have authenticated into the given app (owner-only). */\n    async get_users({\n        app_uuid,\n        limit,\n        offset,\n    }: {\n        app_uuid?: string;\n        limit?: unknown;\n        offset?: unknown;\n    } = {}): Promise<\n        Array<{ user: string; user_uuid: string; user_email?: string | null }>\n    > {\n        if (!app_uuid) throw new HttpError(400, 'Missing `app_uuid`');\n\n        const safeLimit = parseIntParam(limit, {\n            key: 'limit',\n            min: 1,\n            max: MAX_LIMIT,\n            fallback: DEFAULT_LIMIT,\n        });\n        const safeOffset = parseIntParam(offset, {\n            key: 'offset',\n            min: 0,\n            max: MAX_OFFSET,\n            fallback: 0,\n        });\n\n        const app = await this.stores.app.getByUid(app_uuid);\n        if (!app) throw new HttpError(404, 'App not found');\n\n        // The `apps-of-user:<uuid>:write` implicator keys on the owner's","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/extensions/appTelemetry.ts#L91-L127","documentation":"Thrown by VideoGenerationDriver.#assertWriteAccess after `acl.check(actor, parentPath, 'write')` returns false. The destination's PARENT directory must grant the actor write permission. This is distinct from cannot_write_to_root (path shape) and from auth failures — the actor is authenticated but lacks write rights on the target folder.","triggerScenarios":"Generating a video into a directory the actor does not own and has not been granted write access to: another user's folder, a read-only share, or a system folder. The ACL check is performed on pathPosix.dirname(resolvedPath).","commonSituations":"Shared directory set to read-only; app token scoped to a different user; cross-user write attempted without an explicit grant; writing into a path derived from a file-picker that returned a non-owned location.","solutions":["Write into a directory the actor owns (the user's home or an app-owned folder).","Have the directory owner grant the actor write permission before the call.","Verify the destination is under the actor's root via a stat/lookup before submitting the generation job.","Surface a permission prompt in the UI so the user can re-pick an accessible destination."],"exampleFix":"// before — destination owned by another user / read-only share\nawait puter.ai.txt2video({ prompt, path: '/alice/shared/clip.mp4' });\n\n// after — destination the signed-in user owns\nawait puter.ai.txt2video({ prompt, path: '~/Videos/clip.mp4' });","handlingStrategy":"try-catch","validationCode":"// Verify ownership/permission before submitting the (expensive) generation.\ntry {\n  const parent = dest.slice(0, dest.lastIndexOf('/')) || '/';\n  const stat = await puter.fs.stat(parent);\n  if (stat.uid !== currentUser.uid && !stat.is_dir) throw new Error('pick an owned dir');\n} catch { /* fall through; let server reject with access_denied */ }","typeGuard":"function isOwnedPath(p, userHome) {\n  return typeof p === 'string' && p.startsWith(userHome);\n}","tryCatchPattern":"try { await puter.ai.txt2video({ prompt, path: dest }); }\ncatch (e) {\n  if (e?.code === 'access_denied') { showPickWritableFolder(); return; }\n  throw e;\n}","preventionTips":["Default the destination to the signed-in user's home / a known writable folder.","Do not write into shared or another user's directories without an explicit grant.","After any permission change, re-stat the destination before retrying."],"tags":["ai-video","acl","permissions","filesystem"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}