Budibase/budibase · error

Unable to remove doc without a valid _id and _rev.

Error message

Unable to remove doc without a valid _id and _rev.

What it means

remove deletes a document by _id and _rev; CouchDB requires both. When called with an object lacking _id/_rev or an id string without a rev, the wrapper refuses to issue the delete and throws, avoiding guaranteed CouchDB failures.

Source

Thrown at packages/backend-core/src/db/couch/DatabaseImpl.ts:282

    return rows.map(row => (includeDocs ? row.doc! : row.value))
  }

  async remove(idOrDoc: string | Document, rev?: string) {
    // not a read call - but don't create a DB to delete a document
    return this.performCall(db => {
      let _id: string
      let _rev: string

      if (isDocument(idOrDoc)) {
        _id = idOrDoc._id!
        _rev = idOrDoc._rev!
      } else {
        _id = idOrDoc
        _rev = rev!
      }

      if (!_id || !_rev) {
        throw new Error("Unable to remove doc without a valid _id and _rev.")
      }
      return () => db.destroy(_id, _rev)
    })
  }

  async bulkRemove(documents: Document[], opts?: { silenceErrors?: boolean }) {
    const response: Nano.DocumentBulkResponse[] = await this.performCall(db => {
      return () =>
        db.bulk({
          docs: documents.map(doc => ({
            ...doc,
            _deleted: true,
          })),
        })
    })
    if (opts?.silenceErrors) {
      return
    }

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Fetch the doc first (db.get) to obtain _id and _rev, then remove it
  2. Pass the rev explicitly: db.remove(id, rev)
  3. Validate the doc shape before calling remove

Example fix

// before
await db.remove(doc) // doc may lack _rev
// after
const existing = await db.get(doc._id)
await db.remove(existing._id, existing._rev)
Defensive patterns

Strategy: validation

Validate before calling

const canRemove = (doc: Document): doc is Document & { _id: string; _rev: string } =>
  typeof doc._id === "string" && typeof doc._rev === "string"
if (!canRemove(doc)) throw new Error("doc needs _id and _rev before remove")
await db.remove(doc)

Type guard

const isRemovable = (d: Document): d is Document & { _id: string; _rev: string } =>
  !!(d as any)._id && !!(d as any)._rev

Try / catch

try {
  await db.remove(doc)
} catch (err) {
  if (err.message.includes("without a valid _id and _rev")) {
    const existing = await db.get(doc._id)
    await db.remove(existing)
  } else throw err
}

Prevention

When it happens

Trigger: remove(doc) where doc has no _rev (fetched without revs or constructed in memory), or remove(id) without the rev argument (undefined/null rev).

Common situations: Docs built client-side without revs, using stale objects whose _rev was stripped by serialization, forgetting to pass rev when calling remove(id, rev).

Related errors


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