{"record":{"id":"218f0af732bd608e","repo":"linshenkx/prompt-optimizer","slug":"message-content-must-be-a-string","errorCode":null,"errorMessage":"Message content must be a string","messagePattern":"Message content must be a string","errorType":"validation","errorClass":"RequestConfigError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/llm/adapters/abstract-adapter.ts","lineNumber":197,"sourceCode":"    if (!Array.isArray(messages)) {\n      throw new RequestConfigError('Messages must be an array')\n    }\n\n    if (messages.length === 0) {\n      throw new RequestConfigError('Messages array cannot be empty')\n    }\n\n    for (const msg of messages) {\n      if (!msg.role || !msg.content) {\n        throw new RequestConfigError('Each message must have role and content')\n      }\n\n      if (!['system', 'user', 'assistant', 'tool'].includes(msg.role)) {\n        throw new RequestConfigError(`Invalid message role: ${msg.role}`)\n      }\n\n      if (typeof msg.content !== 'string') {\n        throw new RequestConfigError('Message content must be a string')\n      }\n    }\n  }\n\n  protected validateImageUnderstandingRequest(request: ImageUnderstandingRequest): void {\n    if (!request || typeof request !== 'object') {\n      throw new RequestConfigError('Image understanding request cannot be empty')\n    }\n\n    if (typeof request.userPrompt !== 'string' || !request.userPrompt.trim()) {\n      throw new RequestConfigError('Image understanding user prompt cannot be empty')\n    }\n\n    if (!Array.isArray(request.images) || request.images.length === 0) {\n      throw new RequestConfigError('Image understanding request requires at least one image')\n    }\n\n    request.images.forEach((image, index) => {","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/llm/adapters/abstract-adapter.ts#L179-L215","documentation":"Thrown by validateMessages when a message's content is present but is not a string (e.g. a number, object, or array). The adapter's request serialization expects plain string content; multimodal/content-part arrays are not supported by this validation path. It is a client-side RequestConfigError raised before any network request.","triggerScenarios":"Passing content as a number (content: 42), a content-parts array (content: [{type:'text',...}]), or an object; JSON.parse results where content ended up as a non-string value.","commonSituations":"Reusing OpenAI multimodal content arrays; interpolating computed values into content without String(); loose typing where Message['content'] is any.","solutions":["Stringify content before sending: String(value) or JSON.stringify for structured data","For multimodal/image input, use the dedicated sendImageUnderstanding API instead of message content arrays","Type messages strictly so content: string is enforced at compile time"],"exampleFix":"// before\nmessages = [{ role: 'user', content: [{ type: 'text', text: 'hi' }] }]\n\n// after\nmessages = [{ role: 'user', content: 'hi' }]","handlingStrategy":"validation","validationCode":"messages.forEach(m => { if (typeof m.content !== 'string') m.content = String(m.content) })","typeGuard":"function hasStringContent(m: unknown): m is Message {\n  return !!m && typeof (m as Message).content === 'string'\n}","tryCatchPattern":"null","preventionTips":["Keep Message.content strictly typed as string","JSON.stringify structured payloads instead of passing objects","Use sendImageUnderstanding for multimodal input, not message content"],"tags":["validation","messages","type-mismatch","llm"],"backgroundTag":"message-content-type-invalid","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}