{"record":{"id":"01fa6e1eb47ae824","repo":"hyperledger/fabric","slug":"invalid-key-x-must-be-a-utf-8-string","errorCode":null,"errorMessage":"invalid key [%x], must be a UTF-8 string","messagePattern":"invalid key \\[%x\\], must be a UTF-8 string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go","lineNumber":288,"sourceCode":"\tif err := json.Unmarshal(couchDoc.jsonValue, dataformatInfo); err != nil {\n\t\terr = errors.Wrapf(err, \"failed to unmarshal json [%#v] into dataformatInfo\", couchDoc.jsonValue)\n\t\tlogger.Errorf(\"%+v\", err)\n\t\treturn \"\", err\n\t}\n\treturn dataformatInfo.Version, nil\n}\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()","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go#L270-L306","documentation":"validateKey enforces CouchDB document key constraints before any key/value is validated or read: the key must be a valid UTF-8 string. A key with invalid UTF-8 bytes is rejected with 'invalid key [%x], must be a UTF-8 string' (plus checks for '_' prefix and empty keys).","triggerScenarios":"ValidateKeyValue or readFromDB receives a key containing bytes that are not valid UTF-8 (e.g. raw binary keys, truncated multi-byte sequences from string/[]byte conversions).","commonSituations":"Chaincodes using binary/UUID keys stored as raw bytes and cast to string, data arriving over transports that mangle encodings (Latin-1 vs UTF-8), or truncating keys at byte boundaries.","solutions":["Validate keys are valid UTF-8 before PutState/GetState (utf8.Valid([]byte(key)))","Use hex or base64 encoding for binary identifiers so keys are UTF-8 safe","Fix the encoding path that produced the invalid bytes (e.g. ensure string(b) input is UTF-8)"],"exampleFix":"// before\nkey := string(rawBinaryID) // may be invalid UTF-8\nstub.PutState(key, value)\n// after\nif !utf8.Valid(rawBinaryID) {\n    return fmt.Errorf(\"invalid key bytes\")\n}\nkey := hex.EncodeToString(rawBinaryID)\nstub.PutState(key, value)","handlingStrategy":"validation","validationCode":"func validStateKey(key string) error {\n    if !utf8.ValidString(key) { return fmt.Errorf(\"key not valid UTF-8\") }\n    if strings.HasPrefix(key, \"_\") { return fmt.Errorf(\"key cannot begin with _\") }\n    if key == \"\" { return fmt.Errorf(\"key cannot be empty\") }\n    return nil\n}\n// call before PutState/GetState","typeGuard":"func isValidStateKey(key string) bool {\n    return utf8.ValidString(key) && !strings.HasPrefix(key, \"_\") && key != \"\"\n}","tryCatchPattern":"if err := validateKey(key); err != nil {\n    return fmt.Errorf(\"rejecting key before DB access: %w\", err)\n}","preventionTips":["Encode binary IDs as hex/base64 before using them as keys","Validate UTF-8 at the chaincode entry point","Avoid truncating keys mid multi-byte sequence","Run utf8.ValidString in tests over all key samples"],"tags":["utf-8","validation","keys","couchdb","fabric-ledger"],"backgroundTag":"invalid-utf8-key","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"}