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

  1. Validate keys are valid UTF-8 before PutState/GetState (utf8.Valid([]byte(key)))
  2. Use hex or base64 encoding for binary identifiers so keys are UTF-8 safe
  3. 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

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


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/01fa6e1eb47ae824. Report an issue: GitHub.