{"record":{"id":"526ec34b2db12dd5","repo":"Budibase/budibase","slug":"id-and-rev-are-required","errorCode":null,"errorMessage":"_id and _rev are required","messagePattern":"_id and _rev are required","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/agents/crud.ts","lineNumber":532,"sourceCode":"  return await create({\n    name,\n    description: source.description,\n    aiconfig: source.aiconfig,\n    projectIds: await getValidProjectIdsForDuplication(source.projectIds),\n    goal: source.goal,\n    icon: source.icon,\n    iconColor: source.iconColor,\n    live: source.live,\n    _deleted: false,\n    createdBy,\n    operations: source.operations,\n  })\n}\n\nexport async function update(agent: Agent): Promise<Agent> {\n  const { _id, _rev } = agent\n  if (!_id || !_rev) {\n    throw new HTTPError(\"_id and _rev are required\", 400)\n  }\n\n  const db = context.getWorkspaceDB()\n  const existing = await getOrThrow(_id)\n\n  const incomingName = agent.name ?? existing.name\n  const normalizedName = helpers.normalizeForComparison(incomingName)\n  const normalizedExistingName = helpers.normalizeForComparison(existing.name)\n\n  if (normalizedName !== normalizedExistingName) {\n    await guardName(incomingName, _id)\n  }\n\n  const now = new Date().toISOString()\n  const incomingOperations = agent.operations ?? existing.operations ?? []\n  const removedOperations = (existing.operations ?? []).filter(\n    existingOperation =>\n      existingOperation.id &&","sourceCodeStart":514,"sourceCodeEnd":550,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/agents/crud.ts#L514-L550","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Fetch the agent first (getOrThrow) and merge your changes onto the returned document so _id and _rev are present","Check any serialization/HTTP layer for stripping or renaming the _id/_rev fields","If you intended to create rather than update, call create instead","Guard before calling: if (!agent._id || !agent._rev) fetch the doc first"],"exampleFix":"// before\nawait sdk.ai.agents.update({ ...changes })\n// after\nconst existing = await sdk.ai.agents.getOrThrow(agentId)\nawait sdk.ai.agents.update({ ...existing, ...changes })","handlingStrategy":"validation","validationCode":"if (!agent._id || !agent._rev) {\n  const existing = await sdk.ai.agents.getOrThrow(agentId)\n  agent = { ...existing, ...changes }\n}\nawait sdk.ai.agents.update(agent)","typeGuard":"function isPersistedAgent(a: Partial<Agent>): a is Agent & { _id: string; _rev: string } {\n  return typeof a._id === \"string\" && typeof a._rev === \"string\"\n}","tryCatchPattern":"try {\n  await sdk.ai.agents.update(agent)\n} catch (err) {\n  if (err instanceof HTTPError && err.status === 400 && /_id and _rev/.test(err.message)) {\n    // re-fetch the doc and merge changes before updating\n  } else { throw err }\n}","preventionTips":["Always fetch the agent first and spread changes onto the fetched doc","Watch for serialization layers stripping _id/_rev","Use create for new agents, update only for persisted documents"],"tags":["validation","http-400","crud","database"],"backgroundTag":"missing-revision-metadata","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}