HeyPuter/puter · error · HttpError

Missing `app_uuid`

Error message

Missing `app_uuid`

What it means

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.

Source

Thrown at extensions/appTelemetry.ts:109

                [DEFAULT_FREE_SUBSCRIPTION]: 2,
                [DEFAULT_TEMP_SUBSCRIPTION]: 2,
            },
        },
    };

    /** Users who have authenticated into the given app (owner-only). */
    async get_users({
        app_uuid,
        limit,
        offset,
    }: {
        app_uuid?: string;
        limit?: unknown;
        offset?: unknown;
    } = {}): Promise<
        Array<{ user: string; user_uuid: string; user_email?: string | null }>
    > {
        if (!app_uuid) throw new HttpError(400, 'Missing `app_uuid`');

        const safeLimit = parseIntParam(limit, {
            key: 'limit',
            min: 1,
            max: MAX_LIMIT,
            fallback: DEFAULT_LIMIT,
        });
        const safeOffset = parseIntParam(offset, {
            key: 'offset',
            min: 0,
            max: MAX_OFFSET,
            fallback: 0,
        });

        const app = await this.stores.app.getByUid(app_uuid);
        if (!app) throw new HttpError(404, 'App not found');

        // The `apps-of-user:<uuid>:write` implicator keys on the owner's

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Write into a directory the actor owns (the user's home or an app-owned folder).
  2. Have the directory owner grant the actor write permission before the call.
  3. Verify the destination is under the actor's root via a stat/lookup before submitting the generation job.
  4. Surface a permission prompt in the UI so the user can re-pick an accessible destination.

Example fix

// before — destination owned by another user / read-only share
await puter.ai.txt2video({ prompt, path: '/alice/shared/clip.mp4' });

// after — destination the signed-in user owns
await puter.ai.txt2video({ prompt, path: '~/Videos/clip.mp4' });
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify ownership/permission before submitting the (expensive) generation.
try {
  const parent = dest.slice(0, dest.lastIndexOf('/')) || '/';
  const stat = await puter.fs.stat(parent);
  if (stat.uid !== currentUser.uid && !stat.is_dir) throw new Error('pick an owned dir');
} catch { /* fall through; let server reject with access_denied */ }

Type guard

function isOwnedPath(p, userHome) {
  return typeof p === 'string' && p.startsWith(userHome);
}

Try / catch

try { await puter.ai.txt2video({ prompt, path: dest }); }
catch (e) {
  if (e?.code === 'access_denied') { showPickWritableFolder(); return; }
  throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/bf45519f9a927b82. Report an issue: GitHub.