HeyPuter/puter · error · HttpError

bad_request

bad_request

Error message

`prompt` must be a non-empty string

What it means

Thrown by GeminiImageProvider.generate() (GeminiImageProvider.ts:88) before any upstream API call when the `prompt` field is not a string or contains only whitespace. It is a hard precondition: the Gemini generateContent path needs a text prompt to embed as the first content part, so an empty/missing prompt cannot produce a meaningful request. The check runs after test_mode short-circuit, so test calls never hit it.

Source

Thrown at src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts:89

    async generate(params: IGenerateParams): Promise<string> {
        const { prompt, test_mode, input_image, input_image_mime_type, model } =
            params;
        let { ratio, input_images, quality } = params;

        const selectedModel =
            (this.models() as IGeminiImageModel[]).find(
                (m) => m.id === model,
            ) ||
            (this.models() as IGeminiImageModel[]).find(
                (m) => m.id === this.getDefaultModel(),
            )!;

        if (test_mode) {
            return 'https://puter-sample-data.puter.site/image_example.png';
        }

        if (typeof prompt !== 'string' || prompt.trim().length === 0) {
            throw new HttpError(400, '`prompt` must be a non-empty string', {
                legacyCode: 'bad_request',
            });
        }

        if (selectedModel.apiType === 'generateImages') {
            return this.#generateWithImagen(prompt, selectedModel, params);
        }

        const allowedRatios = selectedModel.allowedRatios ?? [
            GEMINI_DEFAULT_RATIO,
        ];
        ratio =
            ratio && this.#isValidRatio(ratio, allowedRatios)
                ? ratio
                : allowedRatios[0];

        // Backwards compat: merge singular input_image into input_images
        if (input_image && (!input_images || input_images.length === 0)) {

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Ensure the caller passes a non-empty string as `prompt` before invoking generate().
  2. Validate at the controller/driver boundary: reject requests where prompt is missing or blank, returning bad_request before reaching the provider.
  3. If building prompts dynamically, guard with `if (!prompt?.trim()) return;` or fall back to a default description.

Example fix

// before
await provider.generate({ prompt: userPrompt });

// after
if (typeof userPrompt !== 'string' || userPrompt.trim().length === 0) {
  throw new HttpError(400, 'prompt is required', { legacyCode: 'bad_request' });
}
await provider.generate({ prompt: userPrompt });
Defensive patterns

Strategy: validation

Validate before calling

function assertNonEmptyPrompt(prompt: unknown): asserts prompt is string {
  if (typeof prompt !== 'string' || prompt.trim().length === 0) {
    throw new Error('`prompt` must be a non-empty string');
  }
}
// before calling generate():
assertNonEmptyPrompt(params.prompt);

Type guard

function isValidPrompt(prompt: unknown): prompt is string {
  return typeof prompt === 'string' && prompt.trim().length > 0;
}

Try / catch

try {
  await provider.generate(params);
} catch (e) {
  if (e instanceof HttpError && e.status_code === 400 && e.message.includes('prompt')) {
    // surface a user-friendly validation error
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling provider.generate({}) with no prompt; passing prompt: '' or prompt: ' '; passing prompt: null or prompt: 123; passing prompt: undefined. Any non-string or whitespace-only value reaches line 88 and throws.

Common situations: A controller or driver layer forwards user input without validating `prompt`; a caller passes a form field that was left blank; JSON deserialization yields null where a string was expected; programmatic callers defaulting prompt to an empty string.

Related errors


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