{"record":{"id":"bd2b108c5ac187a9","repo":"hyperledger/fabric","slug":"invalid-key-empty-string-is-not-supported-as-a-ke","errorCode":null,"errorMessage":"invalid key. Empty string is not supported as a key by couchdb","messagePattern":"invalid key\\. Empty string is not supported as a key by couchdb","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go","lineNumber":294,"sourceCode":"}\n\nfunc validateValue(value []byte) error {\n\tisJSON, jsonVal := tryCastingToJSON(value)\n\tif !isJSON {\n\t\treturn nil\n\t}\n\treturn jsonVal.checkReservedFieldsNotPresent()\n}\n\nfunc validateKey(key string) error {\n\tif !utf8.ValidString(key) {\n\t\treturn errors.Errorf(\"invalid key [%x], must be a UTF-8 string\", key)\n\t}\n\tif strings.HasPrefix(key, \"_\") {\n\t\treturn errors.Errorf(\"invalid key [%s], cannot begin with \\\"_\\\"\", key)\n\t}\n\tif key == \"\" {\n\t\treturn errors.New(\"invalid key. Empty string is not supported as a key by couchdb\")\n\t}\n\treturn nil\n}\n\n// removeJSONRevision removes the \"_rev\" if this is a JSON\nfunc removeJSONRevision(jsonValue *[]byte) error {\n\tjsonVal, err := castToJSON(*jsonValue)\n\tif err != nil {\n\t\tlogger.Errorf(\"Failed to unmarshal couchdb JSON data: %+v\", err)\n\t\treturn err\n\t}\n\tjsonVal.removeRevField()\n\tif *jsonValue, err = jsonVal.toBytes(); err != nil {\n\t\tlogger.Errorf(\"Failed to marshal couchdb JSON data: %+v\", err)\n\t}\n\treturn err\n}\n","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go#L276-L312","documentation":"validateKey rejects the empty string as a state key because CouchDB does not allow an empty document _id. This check runs whenever a key is validated on write (ValidateKeyValue) or encountered on read (readFromDB).","triggerScenarios":"Calling ValidateKeyValue with key == \"\", or PutState(ns, \"\", value) in chaincode; also when readFromDB encounters an empty key in stored data.","commonSituations":"Chaincode building composite keys where a component variable is empty; deserialization bugs that drop the key field; migration scripts writing rows with empty key columns.","solutions":["Ensure a non-empty key is supplied before PutState; return a chaincode error to the caller when the key is empty.","Check that all components of a composite key (CreateCompositeKey arguments) are non-empty.","Fix the data source/migration so empty key fields are defaulted or skipped.","For bulk imports, pre-validate records and log/skip entries with empty keys."],"exampleFix":"// before\nif key == \"\" { key = \"\" } // silent empty key\nstub.PutState(key, value)\n// after\nif key == \"\" {\n  return shim.Error(\"state key must be non-empty\")\n}\nstub.PutState(key, value)","handlingStrategy":"validation","validationCode":"if key == \"\" {\n  return fmt.Errorf(\"cannot write state key '%s' in ns '%s': empty key\", key, ns)\n}\nstub.PutState(key, value)","typeGuard":"func isNonEmptyKey(key string) bool { return len(key) > 0 }","tryCatchPattern":null,"preventionTips":["Validate every composite-key component is non-empty before CreateCompositeKey","Fail fast in chaincode when a lookup variable that feeds the key is missing","Add boundary checks in migration/import tools before writing records"],"tags":["couchdb","state-database","validation","ledger"],"backgroundTag":"empty-key-not-allowed","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"}