HeyPuter/puter · error · HttpError

bad_request

bad_request

Error message

`prompt` must be a non-empty string

What it means

Thrown by ReplicateImageGenerationProvider.generate() (ReplicateImageGenerationProvider.ts:79) when prompt is not a string or is whitespace-only. Identical precondition to Gemini's error 360; fires after test_mode short-circuit and model resolution, before actor lookup and cost estimation.

Source

Thrown at src/backend/drivers/ai-image/providers/replicate/ReplicateImageGenerationProvider.ts:79

        return REPLICATE_IMAGE_GENERATION_MODELS;
    }

    getDefaultModel(): string {
        return DEFAULT_MODEL;
    }

    async generate(params: IGenerateParams): Promise<string> {
        const { prompt, test_mode } = params;

        const selectedModel = this.#getModel(params.model);
        const ratio = this.#normalizeRatio(params.ratio);

        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',
            });
        }

        const actor = Context.get('actor');
        if (!actor) {
            throw new HttpError(401, 'actor not found in context', {
                legacyCode: 'unauthorized',
            });
        }

        const filtered = this.#filterAllowedParams(params, selectedModel);
        const aliased = this.#applyParamAliases(filtered, selectedModel);
        const transformed = this.#applyTransforms(aliased, selectedModel);

        const goFast = !!transformed.go_fast;
        const generationMode =
            typeof transformed.generation_mode === 'string'

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Pass a non-empty string prompt.
  2. Validate at the controller/driver boundary before reaching the provider.
  3. Guard dynamic prompt construction with a trim/length check.

Example fix

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

// after
if (typeof dynamicPrompt !== 'string' || dynamicPrompt.trim().length === 0) {
  throw new HttpError(400, 'prompt is required', { legacyCode: 'bad_request' });
}
await provider.generate({ prompt: dynamicPrompt });
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');
  }
}

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 validation error to user
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling generate({}) with no prompt; prompt: '', prompt: ' ', prompt: null, prompt: undefined, or any non-string value.

Common situations: Caller forwards unvalidated user input; form field left blank; programmatic default to empty string.

Related errors


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