Budibase/budibase · error · HTTPError

Revision is required for updates

Error message

Revision is required for updates

What it means

updateAIConfig requires _rev (CouchDB revision) alongside _id to perform an optimistic-concurrency update. Missing _rev would force blind overwrites and break conflict detection, so the endpoint returns 400.

Source

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

    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,
    provider: body.provider,
    credentialsFields: body.credentialsFields,
    model: body.model,

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Fetch the current config (GET) to obtain the latest _rev, then include both _id and _rev in the PUT body.
  2. Do not strip document metadata fields before sending updates.
  3. If conflicts occur (412/409), re-fetch the doc and retry the update with the fresh _rev.
  4. Treat _rev as required in client-side update types so TypeScript surfaces its absence.

Example fix

// before
await api.put("/api/ai/configs", { _id: config._id, name: "Renamed" })
// after
const fresh = (await api.get(`/api/ai/configs/${config._id}`)).data
await api.put("/api/ai/configs", { ...fresh, name: "Renamed" })
Defensive patterns

Strategy: validation

Validate before calling

if (!config._rev) throw new Error("Config _rev is required for updates; fetch the current document first")

Type guard

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

Try / catch

try {
  await api.put("/api/ai/configs", body)
} catch (e) {
  if (e.status === 400 && e.message.includes("Revision is required")) {
    const fresh = await api.get(`/api/ai/configs/${body._id}`)
    await api.put("/api/ai/configs", { ...body, _rev: fresh.data._rev })
  }
}

Prevention

When it happens

Trigger: PUT /api/ai/configs with body containing _id but no _rev; body built from a partial projection of the config that dropped document metadata; consumer built the payload from the create API response shape (no _rev).

Common situations: Client-side state stripped of _rev by a sanitizer/serializer; constructing update payloads by hand from an earlier list response cached before the doc was updated.

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/537e091298f0807f. Report an issue: GitHub.