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
- Fetch the current config (GET) to obtain the latest _rev, then include both _id and _rev in the PUT body.
- Do not strip document metadata fields before sending updates.
- If conflicts occur (412/409), re-fetch the doc and retry the update with the fresh _rev.
- 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
- Treat _rev as mandatory in update types
- Re-fetch the document before each update to get a fresh revision
- Avoid caching documents across long-lived editing sessions
- Do not sanitize away CouchDB metadata fields
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
- Project revision is required.
- Unable to remove doc without a valid _id and _rev.
- Cannot store document without _id field.
- Query ID or Revision is missing
- Invalid bookmark query
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/537e091298f0807f.
Report an issue: GitHub.