HeyPuter/puter · error · HttpError

forbidden

forbidden

Error message

Prompt blocked by policy

What it means

Thrown (HTTP 403, legacy code 'forbidden') when an ai.prompt.validate listener flagged the prompt as disallowed (allow=false, e.g. content moderation/abuse) but no fake-chat model ('fake' or 'abuse') is registered in config. Normally a blocked prompt is silently rerouted to a fake-chat model that returns lorem-ipsum (or a phone-home script for abuse); this throw is the fallback when that reroute target is itself missing. It signals a server-side configuration gap, not a client content violation.

Source

Thrown at src/backend/drivers/ai-chat/ChatCompletionDriver.ts:367

        };

        await this.clients.event.emitAndWait(
            'ai.prompt.validate',
            validateEvent,
            {},
        );

        // Blocked prompts get rerouted to fake-chat. With `event.abuse` we
        // pick the `abuse` model, which embeds `event.custom` (phone-home
        // script for bots, etc.) in its response so the bot's renderer
        // executes it. Without `abuse`, we silently route to the default
        // `fake` model (lorem-ipsum response). Mirrors v1 AIChatService.
        let blocked = false;
        if (!validateEvent.allow) {
            const fakeModelId = validateEvent.abuse ? 'abuse' : 'fake';
            const fakeModel = this.#resolveModel(fakeModelId, 'fake-chat');
            if (!fakeModel) {
                throw new HttpError(403, 'Prompt blocked by policy', {
                    legacyCode: 'forbidden',
                });
            }
            blocked = true;
            model = fakeModel;
            intendedProvider = 'fake-chat';
            if (typeof validateEvent.custom !== 'undefined') {
                args.custom = validateEvent.custom;
            }
        }

        // -- Credit / subscription gates (metering) --------------------
        // Cheap pre-flight: reject when the user can't afford even the
        // approximate input cost, keep subscriber-only models gated, and
        // cap `max_tokens` so output can't exceed remaining credits.
        // Skipped for blocked requests since fake-chat is free and the
        // user shouldn't see a billing error in place of the abuse page.
        if (!blocked) {

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Register a 'fake' (and optionally 'abuse') model in the fake-chat provider config so #resolveModel succeeds.
  2. If moderation is not wanted, disable or remove the listener that sets event.allow=false on ai.prompt.validate.
  3. Verify the model registry entry the driver resolves with the 'fake-chat' intended provider name.
  4. As an end user, rephrase the prompt to avoid the moderation trigger, or contact the instance operator about the missing fake-chat model.

Example fix

// config.json models array — add a fake-chat entry
// before: fake-chat provider has no models registered
// after:
{
  "provider": "fake-chat",
  "id": "fake",
  "intended_provider": "fake-chat"
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const res = await driver.complete(args);
} catch (e) {
  if (e instanceof HttpError && e.status === 403 && e.body?.legacyCode === 'forbidden') {
    // prompt tripped moderation and the instance has no fake-chat model;
    // surface a user-facing 'content not allowed' message rather than retry
    return showModerationNotice();
  }
  throw e;
}

Prevention

When it happens

Trigger: An event handler attached to 'ai.prompt.validate' sets event.allow=false on a request, and the model registry has no entry resolvable by ChatCompletionDriver.#resolveModel(fakeModelId, 'fake-chat') for either the 'fake' or 'abuse' id. Triggered by any chat completion whose prompt matches the moderation/abuse predicate.

Common situations: Self-hosted Puter installs where the fake-chat models were stripped from config.json but a moderation extension is still enabled; or a deploy that registered an abuse-detection listener without shipping the companion fake-chat models. End users see it only if their prompt tripped moderation on such a misconfigured server.

Related errors


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