Budibase/budibase · error · HTTPError

Config ID is required for updates

Error message

Config ID is required for updates

What it means

updateAIConfig performs a CouchDB-style document update and therefore requires the document _id on the body. Without _id it cannot identify which config to update, so it returns 400 'Config ID is required for updates'.

Source

Thrown at packages/server/src/api/controllers/ai/configs.ts:113

    webSearchConfig: body.webSearchConfig,
    configType: body.configType,
    reasoningEffort: body.reasoningEffort,
    isDefault: body.isDefault,
  }

  const newConfig = await sdk.ai.configs.create(createRequest)

  ctx.body = await sanitizeConfig(newConfig)
}

export const updateAIConfig = async (
  ctx: UserCtx<UpdateAIConfigRequest, AIConfigResponse>
) => {
  const body = ctx.request.body

  if (!body._id) {
    throw new HTTPError("Config ID is required for updates", 400)
  }

  if (!body._rev) {
    throw new HTTPError("Revision is required for updates", 400)
  }

  if (!body.name) {
    throw new HTTPError("Config name is required", 400)
  }

  const configType = body.configType ?? AIConfigType.COMPLETIONS

  const updateRequest: RequiredKeys<
    RequiredKeys<Parameters<typeof sdk.ai.configs.update>[0]>
  > = {
    _id: body._id,
    _rev: body._rev,
    name: body.name,

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Include the config's _id in the PUT body (fetch the config first if needed).
  2. Preserve CouchDB metadata (_id, _rev) when transforming/submitting config objects.
  3. Use POST /api/ai/configs to create new configs instead of PUT.
  4. If the id is only known as a route param, merge it into the body before sending.

Example fix

// before
await api.put("/api/ai/configs", { name: "Renamed", _rev: config._rev })
// after
await api.put("/api/ai/configs", { _id: config._id, _rev: config._rev, name: "Renamed" })
Defensive patterns

Strategy: validation

Validate before calling

if (!config._id) throw new Error("Config _id is required before calling update")

Type guard

const hasId = (c: { _id?: string }): c is { _id: string } =>
  typeof c._id === "string" && c._id.length > 0

Try / catch

try {
  await api.put("/api/ai/configs", body)
} catch (e) {
  if (e.status === 400 && e.message.includes("Config ID is required")) {
    // fetch the config by some external key, merge _id/_rev, retry
  }
}

Prevention

When it happens

Trigger: PUT /api/ai/configs with a body lacking _id (e.g. posting a create-shaped payload to the update endpoint); _id lost after stripping document metadata when cloning a config.

Common situations: Client fetches a config, deletes all CouchDB meta fields, then PUTs it back; API consumers confuse the create and update endpoints; mapping the body through a narrower type that drops _id.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/51dab358c987c2a2. Report an issue: GitHub.