{"record":{"id":"cb496a68f89c7b8f","repo":"Budibase/budibase","slug":"couchdb-error-err-message","errorCode":null,"errorMessage":"CouchDB error: ${err.message}","messagePattern":"CouchDB error: (.+?)","errorType":"exception","errorClass":"CouchDBError","httpStatus":null,"severity":"error","filePath":"packages/backend-core/src/db/couch/DatabaseImpl.ts","lineNumber":189,"sourceCode":"    }\n    return this.getDb()\n  }\n\n  // this function fetches the DB and handles if DB creation is needed\n  private async performCallWithDBCreation<T>(\n    call: DBCallback<T>\n  ): Promise<any> {\n    const db = this.getDb()\n    const fnc = await call(db)\n    try {\n      return await fnc()\n    } catch (err: any) {\n      if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {\n        await this.checkAndCreateDb()\n        return await this.performCallWithDBCreation(call)\n      }\n      // stripping the error down the props which are safe/useful, drop everything else\n      throw new CouchDBError(`CouchDB error: ${err.message}`, err)\n    }\n  }\n\n  private async performCall<T>(call: DBCallback<T>): Promise<T> {\n    const db = this.getDb()\n    const fnc = await call(db)\n    try {\n      return await fnc()\n    } catch (err: any) {\n      // stripping the error down the props which are safe/useful, drop everything else\n      throw new CouchDBError(`CouchDB error: ${err.message}`, err)\n    }\n  }\n\n  async get<T extends Document>(id?: string): Promise<T> {\n    return this.performCall(db => {\n      if (!id) {\n        throw new Error(\"Unable to get doc without a valid _id.\")","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/backend-core/src/db/couch/DatabaseImpl.ts#L171-L207","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Read the wrapped cause (err.getStatusCode/cause) to find the root CouchDB status and fix accordingly","For 409 conflicts, fetch the latest rev and retry the write","Verify CouchDB connectivity/credentials and disk space","Implement bounded retry with backoff for transient network errors"],"exampleFix":"// before\nawait db.put(doc) // throws on stale rev\n// after\ntry {\n  await db.put(doc)\n} catch (e) {\n  if (e.statusCode === 409) {\n    const existing = await db.get(doc._id)\n    await db.put({ ...doc, _rev: existing._rev })\n  } else throw e\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await db.put(doc)\n} catch (err) {\n  if (err instanceof CouchDBError && err.statusCode === 409) {\n    // resolve conflict: refetch rev and retry\n  } else if (err instanceof CouchDBError && err.statusCode === 404) {\n    // db recreate already handled; surface to user\n  } else throw err\n}","preventionTips":["Always write docs with a current _rev for updates","Add bounded retry with backoff for transient network errors","Monitor CouchDB health/disk; most non-404 failures are server-side"],"tags":["couchdb","write-conflict","database"],"backgroundTag":"couchdb-error","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}