{"record":{"id":"bb11b7f881e83a2d","repo":"HeyPuter/puter","slug":"bad-request-bb11b7","errorCode":"bad_request","errorMessage":"`prompt` must be a non-empty string","messagePattern":"`prompt` must be a non-empty string","errorType":"http","errorClass":"HttpError","httpStatus":400,"severity":"error","filePath":"src/backend/drivers/ai-image/providers/replicate/ReplicateImageGenerationProvider.ts","lineNumber":79,"sourceCode":"        return REPLICATE_IMAGE_GENERATION_MODELS;\n    }\n\n    getDefaultModel(): string {\n        return DEFAULT_MODEL;\n    }\n\n    async generate(params: IGenerateParams): Promise<string> {\n        const { prompt, test_mode } = params;\n\n        const selectedModel = this.#getModel(params.model);\n        const ratio = this.#normalizeRatio(params.ratio);\n\n        if (test_mode) {\n            return 'https://puter-sample-data.puter.site/image_example.png';\n        }\n\n        if (typeof prompt !== 'string' || prompt.trim().length === 0) {\n            throw new HttpError(400, '`prompt` must be a non-empty string', {\n                legacyCode: 'bad_request',\n            });\n        }\n\n        const actor = Context.get('actor');\n        if (!actor) {\n            throw new HttpError(401, 'actor not found in context', {\n                legacyCode: 'unauthorized',\n            });\n        }\n\n        const filtered = this.#filterAllowedParams(params, selectedModel);\n        const aliased = this.#applyParamAliases(filtered, selectedModel);\n        const transformed = this.#applyTransforms(aliased, selectedModel);\n\n        const goFast = !!transformed.go_fast;\n        const generationMode =\n            typeof transformed.generation_mode === 'string'","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/replicate/ReplicateImageGenerationProvider.ts#L61-L97","documentation":"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.","triggerScenarios":"Calling generate({}) with no prompt; prompt: '', prompt: '   ', prompt: null, prompt: undefined, or any non-string value.","commonSituations":"Caller forwards unvalidated user input; form field left blank; programmatic default to empty string.","solutions":["Pass a non-empty string prompt.","Validate at the controller/driver boundary before reaching the provider.","Guard dynamic prompt construction with a trim/length check."],"exampleFix":"// before\nawait provider.generate({ prompt: dynamicPrompt });\n\n// after\nif (typeof dynamicPrompt !== 'string' || dynamicPrompt.trim().length === 0) {\n  throw new HttpError(400, 'prompt is required', { legacyCode: 'bad_request' });\n}\nawait provider.generate({ prompt: dynamicPrompt });","handlingStrategy":"validation","validationCode":"function assertNonEmptyPrompt(prompt: unknown): asserts prompt is string {\n  if (typeof prompt !== 'string' || prompt.trim().length === 0) {\n    throw new Error('`prompt` must be a non-empty string');\n  }\n}","typeGuard":"function isValidPrompt(prompt: unknown): prompt is string {\n  return typeof prompt === 'string' && prompt.trim().length > 0;\n}","tryCatchPattern":"try {\n  await provider.generate(params);\n} catch (e) {\n  if (e instanceof HttpError && e.status_code === 400 && e.message.includes('prompt')) {\n    // surface validation error to user\n  }\n  throw e;\n}","preventionTips":["Validate prompt at the boundary before any provider call.","Mark prompt required in request schemas.","Reject whitespace-only input explicitly."],"tags":["validation","input-validation","replicate","ai-image","bad-request"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}