Budibase/budibase · error · HTTPError
Unsupported AI config type: ${model.configType}
Error message
Unsupported AI config type: ${model.configType} What it means
validateConfig is the gatekeeper for AI config creation/update against LiteLLM. It only supports configs whose configType is AIConfigType.COMPLETIONS; any other (unknown or future) config type is rejected with HTTP 400 before delegating to validateCompletionsModel. The enum (packages/types/src/documents/global/ai.ts) currently only contains COMPLETIONS, so this fires when a caller supplies a mistyped, stale, or invented configType string.
Source
Thrown at packages/server/src/sdk/workspace/ai/configs/litellm.ts:373
const message = [
"Error validating configuration",
sanitizeLiteLLMErrorMessage(json.error?.message || json.result?.error),
]
.filter(Boolean)
.join(": ")
throw new HTTPError(message, 400)
}
}
export async function validateConfig(model: {
provider: string
name: string
credentialFields: Record<string, string>
configType: AIConfigType
}) {
if (model.configType !== AIConfigType.COMPLETIONS) {
throw new HTTPError(`Unsupported AI config type: ${model.configType}`, 400)
}
return validateCompletionsModel(model)
}
export async function getKeySettings(): Promise<{
keyId: string
secretKey: string
teamId: string
}> {
const db = context.getWorkspaceDB()
const keyDocId = docIds.getLiteLLMKeyID()
let keyConfig = await db.tryGet<LiteLLMKeyConfig>(keyDocId)
if (!keyConfig || !keyConfig.teamId) {
const workspaceId = context.getProdWorkspaceId()
if (!workspaceId) {
throw new HTTPError("Workspace ID is required to configure LiteLLM", 400)
}View on GitHub (pinned to a81a902e9a)
Solutions
- Set configType to "completions" in the request body (or omit it where the controller defaults it to AIConfigType.COMPLETIONS).
- Check the exact enum value in @budibase/types (AIConfigType) rather than guessing the string.
- If a genuinely new config type is needed, extend AIConfigType and add a matching validator in validateConfig.
Example fix
// before
await api.post("/ai/configs", { name: "gpt4o", configType: "chat", ... })
// after
await api.post("/ai/configs", { name: "gpt4o", configType: "completions", ... }) Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = ["completions"]
if (!ALLOWED.includes(config.configType)) {
throw new Error(`configType must be one of ${ALLOWED.join(", ")}, got ${config.configType}`)
} Type guard
function isCompletionsConfig(c: { configType: string }): c is { configType: "completions" } {
return c.configType === "completions"
} Try / catch
try {
await createConfig(cfg)
} catch (e) {
if (e.status === 400 && e.message.startsWith("Unsupported AI config type")) {
cfg.configType = "completions"
await createConfig(cfg)
} else throw e
} Prevention
- Always send configType: "completions" (or omit it to use the server default).
- Import AIConfigType from @budibase/types instead of hardcoding strings.
- Validate payload against the API schema before POST/PUT.
When it happens
Trigger: POST/PUT to the AI config endpoints (create/update in sdk/workspace/ai/configs/index.ts) with body.configType set to anything other than "completions" — e.g. "completion" (typo), "chat", "embedding", or a value from an older client.
Common situations: Hand-rolled API calls to the configs endpoint with a wrong configType; a client SDK or script written against an older/preview enum; copying config JSON between environments where the type drifted.
Related errors
- Invalid status query
- Invalid bookmark query
- Invalid limit query
- Limit query must be between 1 and 100
- Invalid ${queryName} query
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/bfb2661f9245d3f9.
Report an issue: GitHub.