Budibase/budibase · error · HTTPError
_id or _rev fields missing
Error message
_id or _rev fields missing
What it means
update() persists an edited automation by replacing the stored document, so both the CouchDB _id and _rev must be present; _rev is required for optimistic concurrency. It throws this 400 HTTPError when either is missing on the automation passed in.
Source
Thrown at packages/server/src/sdk/workspace/automations/crud.ts:151
automation = await checkForWebhooks({
newAuto: automation,
})
const response = await db.put(automation)
await events.automation.created(automation)
for (let step of automation.definition.steps) {
await events.automation.stepCreated(automation, step)
}
automation._rev = response.rev
automation._id = response.id
return maskAutomationSecrets(automation)
}
export async function update(automation: Automation) {
automation = trimUnexpectedObjectFields(automation)
validateStickyNoteLimit(automation)
if (!automation._id || !automation._rev) {
throw new HTTPError("_id or _rev fields missing", 400)
}
const db = getDb()
const oldAutomation = await db.get<Automation>(automation._id)
guardInvalidUpdatesAndThrow(automation, oldAutomation)
automation = hydrateAutomationSecrets(automation, oldAutomation)
automation = cleanAutomationInputs(automation)
automation = await checkForWebhooks({
oldAuto: oldAutomation,
newAuto: automation,
})
const response = await db.put(automation)
automation._rev = response.rev
const oldAutoTrigger =View on GitHub (pinned to a81a902e9a)
Solutions
- Fetch the automation first and mutate the fetched object (which includes _id and _rev) before calling update().
- Ensure your HTTP client does not strip _id/_rev fields during serialization.
- Use the create endpoint for brand-new automations instead of update().
Example fix
// before
await api.post("/api/automations", { name: "my auto", ... }) // update call, no _id/_rev
// after
const existing = await api.get(`/api/automations/${id}`)
await api.put(`/api/automations`, { ...existing, ...changes }) // keeps _id and _rev Defensive patterns
Strategy: validation
Validate before calling
function canUpdate(a: Automation): boolean {
return typeof a._id === "string" && a._id.length > 0 && typeof a._rev === "string" && a._rev.length > 0
}
if (!canUpdate(automation)) throw new Error("fetch the automation before updating")
await sdk.automations.update(automation) Type guard
const isPersisted = (a: Automation): a is Automation & { _id: string; _rev: string } =>
typeof a._id === "string" && a._id.length > 0 && typeof a._rev === "string" && a._rev.length > 0 Try / catch
try {
await sdk.automations.update(automation)
} catch (e) {
if (e instanceof HTTPError && e.status === 400 && e.message.includes("_id or _rev")) {
const fresh = await sdk.automations.get(automation._id!)
return sdk.automations.update({ ...fresh, ...automation })
}
throw e
} Prevention
- Always GET the automation before PUT
- Don't strip underscore-prefixed fields in serializers
- Use create for new automations, update only for fetched ones
When it happens
Trigger: Calling the automation update endpoint / sdk.automations.update(automation) with an automation object lacking _id or _rev — e.g. a newly built object that was never fetched, or one stripped of metadata.
Common situations: Client constructed the automation from scratch instead of GET-then-PUT; serialization dropped underscore-prefixed fields; create/update endpoints confused (create doesn't need _rev, update does).
Related errors
- Field ${readonlyField} is readonly and it cannot be modified
- Automations cannot have more than ${MAX_STICKY_NOTES_PER_AUT
- IMAP password is required
- Unable to remove doc without a valid _id and _rev.
- Cannot store document without _id field.
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/e86763730363b0cc.
Report an issue: GitHub.