{"record":{"id":"5192602d25fc408c","repo":"hyperledger/fabric","slug":"error-handling-couchdb-request-error-s-status","errorCode":null,"errorMessage":"error handling CouchDB request. Error:%s,  Status Code:%v,  Reason:%s","messagePattern":"error handling CouchDB request\\. Error:(.+?),  Status Code:(.+?),  Reason:(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdb.go","lineNumber":1739,"sourceCode":"\t// this is a structure and StatusCode is an int\n\t// This is meant to provide a more graceful error if this should occur\n\tif invalidCouchDBReturn(resp, errResp) {\n\t\treturn nil, nil, errors.New(\"unable to connect to CouchDB, check the hostname and port\")\n\t}\n\n\t// set the return code for the couchDB request\n\tcouchDBReturn.StatusCode = resp.StatusCode\n\n\t// check to see if the status code from couchdb is 400 or higher\n\t// response codes 4XX and 500 will be treated as errors -\n\t// golang error will be created from the couchDBReturn contents and both will be returned\n\tif resp.StatusCode >= http.StatusBadRequest {\n\n\t\t// if the status code is 400 or greater, log and return an error\n\t\tcouchdbLogger.Debugf(\"Error handling CouchDB request. Error:%s,  Status Code:%v,  Reason:%s\",\n\t\t\tcouchDBReturn.Error, resp.StatusCode, couchDBReturn.Reason)\n\n\t\treturn nil, couchDBReturn, errors.Errorf(\"error handling CouchDB request. Error:%s,  Status Code:%v,  Reason:%s\",\n\t\t\tcouchDBReturn.Error, resp.StatusCode, couchDBReturn.Reason)\n\n\t}\n\n\tcouchdbLogger.Debugf(\"Exiting handleRequest()\")\n\n\t// If no errors, then return the http response and the couchdb return object\n\treturn resp, couchDBReturn, nil\n}\n\nfunc (couchInstance *couchInstance) recordMetric(startTime time.Time, dbName, api string, couchDBReturn *dbReturn) {\n\tcouchInstance.stats.observeProcessingTime(startTime, dbName, api, strconv.Itoa(couchDBReturn.StatusCode))\n}\n\n// invalidCouchDBReturn checks to make sure either a valid response or error is returned\nfunc invalidCouchDBReturn(resp *http.Response, errResp error) bool {\n\tif resp == nil && errResp == nil {\n\t\treturn true","sourceCodeStart":1721,"sourceCodeEnd":1757,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdb.go#L1721-L1757","documentation":"This error is returned by handleRequest in the statecouchdb package when CouchDB responds with an HTTP status code of 400 or greater. It carries the CouchDB JSON error body (Error and Reason fields) plus the status code, so it represents a server-side rejection of a CouchDB API request (bad request, not found, unauthorized, conflict, etc.). The library raises it for any non-2xx-below-400... i.e. any 4xx/5xx response from the CouchDB HTTP endpoint.","triggerScenarios":"Any couchdb.go client call (CreateDatabase, SaveDoc, ReadDoc, QueryDocuments, DeleteDoc, EnsureFullCommit, etc.) that receives a response with StatusCode >= 400 from the CouchDB server, e.g. 401 bad credentials, 404 missing db/doc, 409 write conflict, 412 db exists.","commonSituations":"Wrong CouchDB username/password in core.yaml or env; database deleted externally; concurrent transaction writes hitting 409 conflicts; CouchDB restarting or overloaded returning 5xx; document too large or malformed rev passed by the caller.","solutions":["Read the Status Code and Reason fields in the returned couchDBReturn value to identify the exact CouchDB error (e.g. 401 -> fix credentials, 404 -> ensure database exists, 409 -> retry with correct _rev).","Verify CouchDB connection settings (address, port, username, password) in the ledger state database config.","Check the CouchDB server logs and health (GET /_up) to rule out server-side outages.","For 409 conflicts on writes, ensure revision handling is correct and retry the transaction."],"exampleFix":"// before: ignoring the detailed CouchDB error\nif err != nil { return err }\n// after: inspect status code and reason\nif err != nil {\n    var couchErr *couchdb.Error // or inspect returned couchDBReturn\n    log.Errorf(\"couchdb request failed: status=%v reason=%s\", ...)\n    if strings.Contains(err.Error(), \"401\") { /* fix credentials */ }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// pre-check CouchDB reachability\nresp, err := http.Get(\"http://admin:pass@localhost:5984/\")\nif err != nil || resp.StatusCode != 200 { /* fix config before peer start */ }","typeGuard":"func isCouchDBStatusError(err error) (code int, reason string, ok bool) {\n    var ce *couchdb.CouchDBError // or inspect the returned couchDBReturn struct\n    if errors.As(err, &ce) { return ce.StatusCode, ce.Reason, true }\n    return 0, \"\", false\n}","tryCatchPattern":"if err != nil {\n    var cErr *couchdb.Error\n    if errors.As(err, &cErr) {\n        switch {\n        case cErr.StatusCode == 401: // fix credentials\n        case cErr.StatusCode == 404: // ensure db exists\n        case cErr.StatusCode == 409: // retry with correct rev\n        default: // log and surface\n        }\n    }\n    return err\n}","preventionTips":["Validate CouchDB credentials and endpoint before starting the peer.","Monitor CouchDB health endpoint (/_up) in deployment.","Log status code and reason from couchDBReturn for diagnosis.","Handle 409 write conflicts with retry/backoff in chaincode design."],"tags":["couchdb","http-error","state-database"],"backgroundTag":"couchdb-request-failed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}