{"record":{"id":"3bb7f158be29eb11","repo":"Budibase/budibase","slug":"cannot-store-document-without-id-field","errorCode":null,"errorMessage":"Cannot store document without _id field.","messagePattern":"Cannot store document without _id field\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/backend-core/src/db/couch/DatabaseImpl.ts","lineNumber":326,"sourceCode":"    }\n    if (errorFound) {\n      throw new CouchDBError(errorMessage, {\n        name: this.name,\n        status: 400,\n      })\n    }\n  }\n\n  async post(document: AnyDocument, opts?: DatabasePutOpts) {\n    if (!document._id) {\n      document._id = newid()\n    }\n    return this.put(document, opts)\n  }\n\n  async put(document: AnyDocument, opts?: DatabasePutOpts) {\n    if (!document._id) {\n      throw new Error(\"Cannot store document without _id field.\")\n    }\n    return this.performCallWithDBCreation(async db => {\n      if (!document.createdAt) {\n        document.createdAt = new Date().toISOString()\n      }\n      document.updatedAt = new Date().toISOString()\n      if (opts?.force && document._id) {\n        try {\n          const existing = await this.get(document._id)\n          if (existing) {\n            document._rev = existing._rev\n          }\n        } catch (err: any) {\n          if (err.status !== 404) {\n            throw err\n          }\n        }\n      }","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/backend-core/src/db/couch/DatabaseImpl.ts#L308-L344","documentation":"put() in DatabaseImpl requires every stored document to carry an _id field; calling put with an _id-less document throws immediately. Documents must be created without a caller-chosen id via post(), which generates one. Timestamps (createdAt/updatedAt) are also stamped here before persistence.","triggerScenarios":"Calling db.put({...}) on an object lacking _id — e.g. building a doc from scratch, spreading a partial payload, or destructuring that drops the _id field.","commonSituations":"Mistakenly using put instead of post for new documents; constructing docs in migrations/scripts without copying _id; API payloads that omit _id; JSON.parse of a list that stripped the underscore-prefixed key.","solutions":["Use db.post(doc) instead of put when creating a new document without an id","Ensure the document object includes _id before calling put (e.g. from a fetched row)","Add a validation/normalization step that rejects or rejects-with-default _id payloads","If an id should be derived, set it explicitly: doc._id = doc._id ?? generateId()"],"exampleFix":"// before\nawait db.put({ name: \"row1\" })\n// after\nawait db.post({ name: \"row1\" }) // or await db.put({ ...doc, _id: doc._id ?? newid() })","handlingStrategy":"validation","validationCode":"if (!doc._id) throw new Error(\"Document requires _id before put(); use post() to create\")","typeGuard":"function hasId(doc: Record<string, unknown>): doc is Record<string, unknown> & { _id: string } {\n  return typeof doc._id === \"string\" && doc._id.length > 0\n}","tryCatchPattern":null,"preventionTips":["Use post() for new documents, put() only for updates","Normalize API payloads to preserve underscore-prefixed CouchDB fields","Assert doc._id presence in a shared persist helper"],"tags":["couchdb","validation","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}