{"record":{"id":"a892178300364c02","repo":"gitbutlerapp/gitbutler","slug":"invalid-prompt-must-be-a-non-empty-array","errorCode":null,"errorMessage":"Invalid prompt: must be a non-empty array","messagePattern":"Invalid prompt: must be a non-empty array","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/lib/ai/lmStudioClient.ts","lineNumber":40,"sourceCode":"\n\tprivate baseUrl: string;\n\tprivate modelName: string;\n\n\tconstructor(endpoint: string, modelName: string) {\n\t\tthis.modelName = modelName;\n\t\t// Format the base URL to ensure it ends with /v1\n\t\tthis.baseUrl = endpoint.endsWith(\"/v1\")\n\t\t\t? endpoint\n\t\t\t: endpoint.endsWith(\"/\")\n\t\t\t\t? `${endpoint}v1`\n\t\t\t\t: `${endpoint}/v1`;\n\t}\n\n\tasync evaluate(prompt: Prompt, options?: AIEvalOptions): Promise<string> {\n\t\ttry {\n\t\t\t// Validate input\n\t\t\tif (!prompt || !Array.isArray(prompt) || prompt.length === 0) {\n\t\t\t\tthrow new Error(\"Invalid prompt: must be a non-empty array\");\n\t\t\t}\n\n\t\t\t// Format messages for the API\n\t\t\tconst messages = prompt.map((msg) => ({\n\t\t\t\trole: msg.role.toLowerCase(),\n\t\t\t\tcontent: msg.content,\n\t\t\t}));\n\n\t\t\t// Determine if we should stream the response\n\t\t\tconst shouldStream = options?.onToken !== undefined;\n\n\t\t\t// Make request to the LM Studio API\n\t\t\tconst response = await fetch(`${this.baseUrl}/chat/completions`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/apps/desktop/src/lib/ai/lmStudioClient.ts#L22-L58","documentation":"LMStudioClient.evaluate() validates its `prompt` argument before sending anything to the LM Studio server. It requires a non-empty array of Prompt messages; anything falsy, non-array, or an empty array is rejected. This guards against calling the chat completions endpoint with no messages.","triggerScenarios":"Calling evaluate() with null/undefined, with a non-array value (e.g. a plain string), or with an empty array [].","commonSituations":"Prompt-building code that returns [] when no messages were collected; passing a single string instead of an array of messages; uninitialized prompt variable; a caller that filters messages and ends up with an empty list.","solutions":["Ensure the prompt is an array of message objects with role and content before calling evaluate().","Check that your prompt-building logic never returns an empty array; add a fallback or early return.","If a single message, wrap it: [{ role: 'user', content: '...' }]."],"exampleFix":"// before\nawait client.evaluate('hello');\n// after\nawait client.evaluate([{ role: 'User', content: 'hello' }]);","handlingStrategy":"validation","validationCode":"if (!Array.isArray(prompt) || prompt.length === 0) {\n  throw new Error('prompt must be a non-empty array of messages');\n}\nawait client.evaluate(prompt);","typeGuard":"function isValidPrompt(p: unknown): p is Prompt {\n  return Array.isArray(p) && p.length > 0 && p.every(m => m && typeof m.role === 'string' && typeof m.content === 'string');\n}","tryCatchPattern":"try {\n  await client.evaluate(prompt);\n} catch (e) {\n  if (e.message.includes('Invalid prompt')) {\n    // fall back to a default prompt or surface a user-facing validation error\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always build prompts via a helper that guarantees at least one message.","Wrap single strings into [{ role, content }] at the call site.","Add a unit test asserting the prompt builder never returns []."],"tags":["validation","argument","ai"],"backgroundTag":"empty-required-field","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}