HeyPuter/puter · warning · HttpError

Authentication required

Error message

Authentication required

What it means

Gemini completed the operation but the response carried raiMediaFilteredCount > 0 and zero generatedVideos — Google's Responsible AI filter rejected the output. The driver surfaces this as 400 disallowed_value (not 500) because it is a client/content problem, not an outage. The reasons come from raiMediaFilteredReasons, falling back to 'content policy'.

Source

Thrown at extensions/appTelemetry.ts:137

            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
        // UUID, not the numeric id. Look up the owner explicitly — the raw
        // app row only carries `owner_user_id`. (v1 got the owner for free
        // because its entity-storage layer eager-joined the owner row.)
        const ownerId = (app as { owner_user_id?: number }).owner_user_id;
        if (!ownerId) throw new HttpError(404, 'App owner not found');
        const owner = await this.stores.user.getById(ownerId);
        if (!owner?.uuid) throw new HttpError(404, 'App owner not found');

        const actor = Context.get('actor');
        if (!actor) throw new HttpError(401, 'Authentication required');
        const ownsApp = await this.services.permission
            .check(actor as Actor, `apps-of-user:${owner.uuid}:write`)
            .catch(() => false);
        if (!ownsApp) throw new HttpError(403, 'Permission denied');

        const appId = (app as { id: number }).id;

        const users = (await this.clients.db.read(
            `SELECT u.id, u.username, u.uuid, u.email FROM user_to_app_permissions p
             INNER JOIN ${this.clients.db.quoteIdentifier('user')} u ON p.user_id = u.id
             WHERE p.permission = 'flag:app-is-authenticated' AND p.app_id = ?
             ORDER BY (p.dt IS NOT NULL), p.dt, p.user_id
             LIMIT ? OFFSET ?`,
            [appId, safeLimit, safeOffset],
        )) as Array<{
            id: number;
            username: string;
            uuid: string;

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Rephrase the prompt to remove policy-sensitive terms; re-read the reasons string in the error message.
  2. If using reference_images / last_frame, replace or re-crop the flagged input asset.
  3. Offer the user an edit step before retry rather than auto-retrying the same payload.
  4. Track which prompts filter repeatedly and surface a UI hint to revise them.

Example fix

// before
const url = await puter.ai.txt2video({ prompt: userPrompt, model: 'gemini-2.5-video' });

// after — catch the filter and let the user revise
try {
  const url = await puter.ai.txt2video({ prompt: userPrompt, model: 'gemini-2.5-video' });
} catch (e) {
  if (e?.code === 'disallowed_value') {
    showUser('The provider rejected this prompt. Please rephrase it.');
    return;
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Try / catch

try { return await puter.ai.txt2video(params); }
catch (e) {
  if (e?.code === 'disallowed_value') {
    notifyUser(`Provider blocked this prompt (${e.message}). Please revise it.`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Submitting a prompt (or reference image / last-frame) whose content triggers Gemini's RAI filter — violence, sexual content, public figures, disallowed topics. The job reaches 'complete' but every candidate was filtered.

Common situations: Prompt with policy-sensitive wording; reference image flagged by the vision safety model; locale/account under stricter policy tier; prompt that was fine at low safety but blocked at the model's configured safety threshold.

Understand the failure class

Related errors


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