hyperledger/fabric · error
invalid key [%s], cannot begin with "_"
Error message
invalid key [%s], cannot begin with "_"
What it means
validateKey enforces CouchDB document-key rules before a key becomes a CouchDB _id. Keys starting with an underscore are rejected because CouchDB reserves the '_'-prefixed field names (like _id, _rev, _design) for its own document metadata; storing such a key would collide with that namespace.
Source
Thrown at core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go:291
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()
if *jsonValue, err = jsonVal.toBytes(); err != nil {
logger.Errorf("Failed to marshal couchdb JSON data: %+v", err)
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Rename the key so it does not start with '_' (prefix with a safe character, e.g. 'x_' or strip/replace the leading underscore).
- Sanitize keys at the application boundary before PutState, rejecting or remapping underscore-prefixed names.
- If the data came from an import/migration, re-run the migration with key transformation applied.
- If the key must start with '_' semantically, use LevelDB (stateleveldb) as the state database instead of CouchDB.
Example fix
// before
ctx.GetStub().PutState("_userCounter", []byte("1"))
// after
ctx.GetStub().PutState("userCounter", []byte("1")) Defensive patterns
Strategy: validation
Validate before calling
func validStateKey(key string) error {
if !utf8.ValidString(key) { return fmt.Errorf("key not UTF-8: %x", key) }
if strings.HasPrefix(key, "_") { return fmt.Errorf("key must not start with '_': %s", key) }
if key == "" { return errors.New("key must be non-empty") }
return nil
}
// call before PutState
if err := validStateKey(key); err != nil { return err } Type guard
func isSafeKey(key string) bool {
return key != "" && !strings.HasPrefix(key, "_") && utf8.ValidString(key)
} Prevention
- Never build state keys from raw JSON field names without sanitizing leading underscores
- Centralize key construction in one helper that enforces the no-leading-underscore rule
- Add unit tests that reject keys like "_id", "_rev", "" before they reach PutState
When it happens
Trigger: Calling ValidateKeyValue with a key whose first character is '_' (e.g. a state key literally named '_config' or '_temp'), or reading a record from the DB (readFromDB) whose stored key begins with '_' — typically after a write that bypassed validation or an external import.
Common situations: Chaincode or migration tooling generating keys from JSON field names that start with '_'; importing legacy data into a CouchDB-backed ledger; keys constructed by concatenating prefixes that produce a leading underscore.
Related errors
- invalid key. Empty string is not supported as a key by couch
- could not retrieve committed definition for chaincode '%s'
- failed obtaining query executor: %v
- the %s database [height=%d] is ahead of the block store [hei
- error during commit to txmgr
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/d6bbb42aff75e8ac.
Report an issue: GitHub.