{"record":{"id":"f45625e6f0b7d6c2","repo":"HeyPuter/puter","slug":"bad-request-f45625","errorCode":"bad_request","errorMessage":"`prompt` must be a non-empty string","messagePattern":"`prompt` must be a non-empty string","errorType":"validation","errorClass":"HttpError","httpStatus":400,"severity":"warning","filePath":"src/backend/drivers/ai-image/providers/xai/XAIImageProvider.ts","lineNumber":75,"sourceCode":"    }\n\n    getDefaultModel(): string {\n        return DEFAULT_MODEL;\n    }\n\n    async generate(params: IGenerateParams): Promise<string> {\n        const { prompt, test_mode, model, ratio, quality } = params;\n        let { input_images } = params;\n        const { input_image, input_image_mime_type } = params;\n\n        const selectedModel = this.#getModel(model);\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        // Backwards compat: fold singular `input_image` into `input_images`.\n        if (input_image && (!input_images || input_images.length === 0)) {\n            input_images = [input_image];\n        }\n        // xAI caps edits at 3 source images.\n        if (input_images && input_images.length > MAX_INPUT_IMAGES) {\n            input_images = input_images.slice(0, MAX_INPUT_IMAGES);\n        }\n        const inputImageCount = input_images?.length ?? 0;\n        const hasInputImages = inputImageCount > 0;\n\n        // xAI uses a `resolution` tier ('1k'/'2k') rather than a pixel size.\n        const resolution = this.#normalizeResolution(quality);\n        const aspectRatio = this.#aspectRatio(ratio);","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/xai/XAIImageProvider.ts#L57-L93","documentation":"The xAI (Grok Imagine) image provider rejects calls where the prompt parameter is not a non-empty string. This validation (line 74) runs after the test_mode short-circuit and before any upstream API call, ensuring the xAI API receives valid text input.","triggerScenarios":"Calling generate() with prompt set to undefined, null, an empty string, a whitespace-only string, or a non-string type. This check mirrors the same validation in the Together and Replicate providers.","commonSituations":"Empty prompt from a UI text field that was not validated; undefined prompt variable due to a missing property in the params object; prompt set to a falsy value by conditional logic upstream.","solutions":["Ensure prompt is a trimmed non-empty string before calling generate().","Validate input on the client side and disable the submit button when the prompt is empty.","Set a sensible default or reject the request early."],"exampleFix":"// before\nconst url = await provider.generate({ prompt: formData.prompt });\n\n// after\nconst prompt = (formData.prompt ?? '').trim();\nif (!prompt) throw new Error('Prompt cannot be empty');\nconst url = await provider.generate({ prompt });","handlingStrategy":"validation","validationCode":"function validatePrompt(prompt: unknown): string {\n  if (typeof prompt !== 'string' || prompt.trim().length === 0) {\n    throw new Error('prompt must be a non-empty string');\n  }\n  return prompt.trim();\n}\n// Use before calling generate:\nconst cleanPrompt = validatePrompt(params.prompt);","typeGuard":"function isValidPrompt(value: unknown): value is string {\n  return typeof value === 'string' && value.trim().length > 0;\n}","tryCatchPattern":null,"preventionTips":["Validate the prompt field client-side before sending the request.","Provide UI feedback (disable submit) when the prompt is empty.","Use test_mode: true in development."],"tags":["xai","image-generation","input-validation","prompt"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}