Budibase/budibase · error · Error
AI system message must be a string
Error message
AI system message must be a string
What it means
generateJs builds an AI request via ai.generateJs and requires the resulting message list to contain a system message whose content is a plain string. If no system-role message exists or its content is not a string (e.g. array of content parts), this Error is thrown before any LLM call is made.
Source
Thrown at packages/server/src/api/controllers/ai/js.ts:22
import { ai } from "@budibase/pro"
import sdk from "../../../sdk"
const MARKDOWN_CODE_BLOCK = /```(?:\w+)?\n([\s\S]+?)\n```/
export async function generateJs(
ctx: UserCtx<GenerateJsRequest, GenerateJsResponse>
) {
await context.ensureSnippetContext()
const currentContext = context.getCurrentContext()
const snippets = currentContext?.snippets || []
const { prompt, bindings = [] } = ctx.request.body
const request = ai.generateJs(bindings, snippets)
const systemMessage = request.messages.find(
message => message.role === "system"
)?.content
if (typeof systemMessage !== "string") {
throw new Error("AI system message must be a string")
}
const { chat, providerOptions } = await sdk.ai.llm.getDefaultLLMOrThrow()
const result = await generateText({
model: chat,
instructions: systemMessage,
prompt,
providerOptions: providerOptions?.(false),
})
let code = result.text || ""
const match = code.match(MARKDOWN_CODE_BLOCK)
if (match) {
code = match[1]
}
ctx.body = { code }
}
View on GitHub (pinned to a81a902e9a)
Solutions
- Update the ai.generateJs helper (or stub) to return a system message with string content.
- If the content is an array of parts, join the text parts before passing: map(part => part.text).join('') or use the SDK's convertToCoreMessages-style helper.
- Pin/align the AI SDK version so generateJs output matches the expected message shape.
Example fix
// before
const systemMessage = request.messages.find(m => m.role === 'system')?.content
// after
const rawContent = request.messages.find(m => m.role === 'system')?.content
const systemMessage = typeof rawContent === 'string' ? rawContent : Array.isArray(rawContent) ? rawContent.map(p => p.text).join('') : undefined Defensive patterns
Strategy: type-guard
Validate before calling
const msgs = ai.generateJs(bindings, snippets).messages
const sys = msgs.find(m => m.role === 'system')
if (!sys || typeof sys.content !== 'string') throw new Error('generateJs must return a string system message') Type guard
function hasStringSystemMessage(messages: { role: string; content: unknown }[]): messages is { role: 'system'; content: string }[] {
const sys = messages.find(m => m.role === 'system')
return typeof sys?.content === 'string'
} Try / catch
try {
const result = await generateJs(bindings, snippets, prompt)
} catch (e) {
if (e.message === 'AI system message must be a string') {
// fall back to a locally-constructed system prompt string
} else throw e
} Prevention
- Pin the AI SDK version; check release notes for message content shape changes.
- Unit-test generateJs output shape, not just the LLM call.
- When stubbing ai.generateJs in tests, include a system message with string content.
When it happens
Trigger: Calling generateJs where ai.generateJs returns messages with no role==='system' entry, or where the system message content is an array/prompt-parts object rather than a string (provider/SDK version drift).
Common situations: Upgrading the AI SDK changed system message serialization to content-part arrays; a custom snippets/bindings path suppresses the system message; tests stub ai.generateJs with incomplete messages.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Error generating tables
- LLM not available
- No response found
- AI user message must be a string
- Could not parse AI response as valid JSON.
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/4fa4f9487f1be697.
Report an issue: GitHub.