hyperledger/fabric · error
invalid key [%x], must be a UTF-8 string
Error message
invalid key [%x], must be a UTF-8 string
What it means
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).
Source
Thrown at core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go:288
if err := json.Unmarshal(couchDoc.jsonValue, dataformatInfo); err != nil {
err = errors.Wrapf(err, "failed to unmarshal json [%#v] into dataformatInfo", couchDoc.jsonValue)
logger.Errorf("%+v", err)
return "", err
}
return dataformatInfo.Version, nil
}
func validateValue(value []byte) error {
isJSON, jsonVal := tryCastingToJSON(value)
if !isJSON {
return nil
}
return jsonVal.checkReservedFieldsNotPresent()
}
func validateKey(key string) error {
if !utf8.ValidString(key) {
return errors.Errorf("invalid key [%x], must be a UTF-8 string", key)
}
if strings.HasPrefix(key, "_") {
return errors.Errorf("invalid key [%s], cannot begin with \"_\"", key)
}
if key == "" {
return errors.New("invalid key. Empty string is not supported as a key by couchdb")
}
return nil
}
// removeJSONRevision removes the "_rev" if this is a JSON
func removeJSONRevision(jsonValue *[]byte) error {
jsonVal, err := castToJSON(*jsonValue)
if err != nil {
logger.Errorf("Failed to unmarshal couchdb JSON data: %+v", err)
return err
}
jsonVal.removeRevField()View on GitHub (pinned to 2736b63f8f)
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)
Example fix
// before
key := string(rawBinaryID) // may be invalid UTF-8
stub.PutState(key, value)
// after
if !utf8.Valid(rawBinaryID) {
return fmt.Errorf("invalid key bytes")
}
key := hex.EncodeToString(rawBinaryID)
stub.PutState(key, value) Defensive patterns
Strategy: validation
Validate before calling
func validStateKey(key string) error {
if !utf8.ValidString(key) { return fmt.Errorf("key not valid UTF-8") }
if strings.HasPrefix(key, "_") { return fmt.Errorf("key cannot begin with _") }
if key == "" { return fmt.Errorf("key cannot be empty") }
return nil
}
// call before PutState/GetState Type guard
func isValidStateKey(key string) bool {
return utf8.ValidString(key) && !strings.HasPrefix(key, "_") && key != ""
} Try / catch
if err := validateKey(key); err != nil {
return fmt.Errorf("rejecting key before DB access: %w", err)
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- JSON format is not valid
- number of retries must be zero or greater
- error creating http request
- database name is illegal, cannot be empty
- database name is illegal, cannot be longer than %d
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/01fa6e1eb47ae824.
Report an issue: GitHub.