{"record":{"id":"7261435648251295","repo":"hyperledger/fabric","slug":"failed-opening-file-s-v","errorCode":null,"errorMessage":"Failed opening file %s: %v","messagePattern":"Failed opening file (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/common/comm/config.go","lineNumber":69,"sourceCode":"\t\t}\n\t\tcertBytes, err = loadFile(conf.CertPath)\n\t\tif err != nil {\n\t\t\treturn comm.SecureOptions{}, errors.WithStack(err)\n\t\t}\n\t}\n\treturn comm.SecureOptions{\n\t\tKey:               keyBytes,\n\t\tCertificate:       certBytes,\n\t\tUseTLS:            true,\n\t\tServerRootCAs:     [][]byte{caBytes},\n\t\tRequireClientCert: true,\n\t}, nil\n}\n\nfunc loadFile(path string) ([]byte, error) {\n\tb, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, errors.Errorf(\"Failed opening file %s: %v\", path, err)\n\t}\n\treturn b, nil\n}\n","sourceCodeStart":51,"sourceCodeEnd":73,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/cmd/common/comm/config.go#L51-L73","documentation":"After reading the _all_docs bulk-response body, the client unmarshals it into batchRetrieveDocMetadataResponse. If the body is not valid JSON or its rows do not match the expected shape (id, rev, doc metadata with version), json.Unmarshal fails and the error is wrapped as 'error unmarshalling json data', aborting retrieval of ledger versions for the batch of keys.","triggerScenarios":"CouchDB (or an intermediary) returns a non-JSON body for the _all_docs POST — e.g. 401/403 HTML or text error page, proxy captive-portal response, truncated JSON from a dropped connection — or a body whose rows[] entries contain unexpected types.","commonSituations":"Wrong CouchDB credentials causing an error response that still gets decoded, an LB returning its own HTML error page, version mismatch where the server's _all_docs response shape differs, corrupted network transfer.","solutions":["Verify CouchDB username/password (ledger.state.couchDBConfig.username/password) so the server returns real JSON, not an auth error page","curl -u user:pass -X POST with {\"keys\":[...]} against /<db>/_all_docs to inspect the actual body","Check for proxies/interceptors returning HTML and bypass them","Confirm Fabric/CouchDB version compatibility","Enable couchdbLogger debug output to capture the raw response for inspection"],"exampleFix":"// before\nresp, err := http.Post(\"http://proxy/db/_all_docs\", ...) // proxy 502 HTML body\njson.Unmarshal(raw, &jsonResponse) // fails\n// after\nif ct := resp.Header.Get(\"Content-Type\"); !strings.HasPrefix(ct, \"application/json\") {\n    return nil, fmt.Errorf(\"unexpected CouchDB response: %.200s\", raw)\n}\nerr2 := json.Unmarshal(jsonResponseRaw, &jsonResponse)","handlingStrategy":"type-guard","validationCode":"raw, _ := io.ReadAll(resp.Body)\nif !json.Valid(raw) {\n    return fmt.Errorf(\"non-JSON _all_docs response: %.200s\", raw)\n}","typeGuard":"func isJSONResponse(resp *http.Response) bool {\n    ct := resp.Header.Get(\"Content-Type\")\n    return strings.HasPrefix(ct, \"application/json\")\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"error unmarshalling json data\") {\n    // dump raw body at debug level, check auth/proxy, then retry\n    return fmt.Errorf(\"bad _all_docs response from CouchDB: %w\", err)\n}","preventionTips":["Verify CouchDB credentials so error responses are never silently decoded","Bypass HTML-emitting proxies for the CouchDB host","Check Content-Type before decoding server responses","Keep Fabric and CouchDB versions compatible","Alert on 401/403/502 statuses from CouchDB in metrics"],"tags":["couchdb","json","unmarshal","fabric"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}