Budibase/budibase · error · CouchDBError

CouchDB error: ${err.message}

Error message

CouchDB error: ${err.message}

What it means

performCallWithDBCreation wraps write operations (put, bulkDocs). If CouchDB reports 404 'database_does_not_exist' it recreates the DB and retries once; any other failure is rethrown as CouchDBError('CouchDB error: ...') with safe properties preserved. This is the generic wrapper error for failed DB calls in the creation-aware path.

Source

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

    }
    return this.getDb()
  }

  // this function fetches the DB and handles if DB creation is needed
  private async performCallWithDBCreation<T>(
    call: DBCallback<T>
  ): Promise<any> {
    const db = this.getDb()
    const fnc = await call(db)
    try {
      return await fnc()
    } catch (err: any) {
      if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
        await this.checkAndCreateDb()
        return await this.performCallWithDBCreation(call)
      }
      // stripping the error down the props which are safe/useful, drop everything else
      throw new CouchDBError(`CouchDB error: ${err.message}`, err)
    }
  }

  private async performCall<T>(call: DBCallback<T>): Promise<T> {
    const db = this.getDb()
    const fnc = await call(db)
    try {
      return await fnc()
    } catch (err: any) {
      // stripping the error down the props which are safe/useful, drop everything else
      throw new CouchDBError(`CouchDB error: ${err.message}`, err)
    }
  }

  async get<T extends Document>(id?: string): Promise<T> {
    return this.performCall(db => {
      if (!id) {
        throw new Error("Unable to get doc without a valid _id.")

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Read the wrapped cause (err.getStatusCode/cause) to find the root CouchDB status and fix accordingly
  2. For 409 conflicts, fetch the latest rev and retry the write
  3. Verify CouchDB connectivity/credentials and disk space
  4. Implement bounded retry with backoff for transient network errors

Example fix

// before
await db.put(doc) // throws on stale rev
// after
try {
  await db.put(doc)
} catch (e) {
  if (e.statusCode === 409) {
    const existing = await db.get(doc._id)
    await db.put({ ...doc, _rev: existing._rev })
  } else throw e
}
Defensive patterns

Strategy: retry

Try / catch

try {
  await db.put(doc)
} catch (err) {
  if (err instanceof CouchDBError && err.statusCode === 409) {
    // resolve conflict: refetch rev and retry
  } else if (err instanceof CouchDBError && err.statusCode === 404) {
    // db recreate already handled; surface to user
  } else throw err
}

Prevention

When it happens

Trigger: Any put/bulkDocs failing for reasons other than missing DB: document validation conflicts (409), quota exceeded (413), CouchDB unreachable (ECONNREFUSED), auth failure (401), or repeated 404 after recreate retry also fails.

Common situations: Writing docs with bad/missing _rev (conflict), CouchDB restarts mid-deploy, full disk, proxy timeouts, invalid doc IDs (must be strings, not starting _ except design docs).

Related errors


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