Budibase/budibase · error · HTTPError

_id and _rev are required

Error message

_id and _rev are required

What it means

update persists changes to an existing agent document. CouchDB-style persistence requires both _id (document key) and _rev (current revision) for an update; if either is missing on the passed Agent object the function throws a 400 HTTPError before any DB access, preventing accidental document creation or revision conflicts.

Source

Thrown at packages/server/src/sdk/workspace/ai/agents/crud.ts:532

  return await create({
    name,
    description: source.description,
    aiconfig: source.aiconfig,
    projectIds: await getValidProjectIdsForDuplication(source.projectIds),
    goal: source.goal,
    icon: source.icon,
    iconColor: source.iconColor,
    live: source.live,
    _deleted: false,
    createdBy,
    operations: source.operations,
  })
}

export async function update(agent: Agent): Promise<Agent> {
  const { _id, _rev } = agent
  if (!_id || !_rev) {
    throw new HTTPError("_id and _rev are required", 400)
  }

  const db = context.getWorkspaceDB()
  const existing = await getOrThrow(_id)

  const incomingName = agent.name ?? existing.name
  const normalizedName = helpers.normalizeForComparison(incomingName)
  const normalizedExistingName = helpers.normalizeForComparison(existing.name)

  if (normalizedName !== normalizedExistingName) {
    await guardName(incomingName, _id)
  }

  const now = new Date().toISOString()
  const incomingOperations = agent.operations ?? existing.operations ?? []
  const removedOperations = (existing.operations ?? []).filter(
    existingOperation =>
      existingOperation.id &&

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Fetch the agent first (getOrThrow) and merge your changes onto the returned document so _id and _rev are present
  2. Check any serialization/HTTP layer for stripping or renaming the _id/_rev fields
  3. If you intended to create rather than update, call create instead
  4. Guard before calling: if (!agent._id || !agent._rev) fetch the doc first

Example fix

// before
await sdk.ai.agents.update({ ...changes })
// after
const existing = await sdk.ai.agents.getOrThrow(agentId)
await sdk.ai.agents.update({ ...existing, ...changes })
Defensive patterns

Strategy: validation

Validate before calling

if (!agent._id || !agent._rev) {
  const existing = await sdk.ai.agents.getOrThrow(agentId)
  agent = { ...existing, ...changes }
}
await sdk.ai.agents.update(agent)

Type guard

function isPersistedAgent(a: Partial<Agent>): a is Agent & { _id: string; _rev: string } {
  return typeof a._id === "string" && typeof a._rev === "string"
}

Try / catch

try {
  await sdk.ai.agents.update(agent)
} catch (err) {
  if (err instanceof HTTPError && err.status === 400 && /_id and _rev/.test(err.message)) {
    // re-fetch the doc and merge changes before updating
  } else { throw err }
}

Prevention

When it happens

Trigger: Calling update with an object that lacks _id or _rev — e.g. passing a newly constructed agent literal, a response from an API that stripped underscore fields, spreading a partial update over nothing, or client code that submitted a payload omitting the CouchDB metadata fields.

Common situations: Frontend sending only changed fields without merging them onto the fetched doc; serialization layers that camelCase/strip _id/_rev; constructing Agent objects manually for tests; attempting to 'update' an agent that was never fetched (no revision available).

Related errors


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