hyperledger/fabric · error

field [%s] is not valid for the CouchDB state database

Error message

field [%s] is not valid for the CouchDB state database

What it means

This error is thrown by checkReservedFieldsNotPresent when a JSON value destined for the CouchDB state database contains a field named 'version' or any field whose name begins with an underscore. CouchDB reserves underscore-prefixed fields (e.g. _id, _rev) and Hyperledger Fabric uses 'version' internally, so user-supplied state JSON must never contain them. The check runs before the value is wrapped into a couchDoc.

Source

Thrown at core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go:53

type jsonValue map[string]any

func tryCastingToJSON(b []byte) (isJSON bool, val jsonValue) {
	var jsonVal map[string]any
	err := json.Unmarshal(b, &jsonVal)
	return err == nil, jsonVal
}

func castToJSON(b []byte) (jsonValue, error) {
	var jsonVal map[string]any
	err := json.Unmarshal(b, &jsonVal)
	err = errors.Wrap(err, "error unmarshalling json data")
	return jsonVal, err
}

func (v jsonValue) checkReservedFieldsNotPresent() error {
	for fieldName := range v {
		if fieldName == versionField || strings.HasPrefix(fieldName, "_") {
			return errors.Errorf("field [%s] is not valid for the CouchDB state database", fieldName)
		}
	}
	return nil
}

func (v jsonValue) removeRevField() {
	delete(v, revField)
}

func (v jsonValue) toBytes() ([]byte, error) {
	jsonBytes, err := json.Marshal(v)
	err = errors.Wrap(err, "error marshalling json data")
	return jsonBytes, err
}

func couchDocToKeyValue(doc *couchDoc) (*keyValue, error) {
	docFields, err := validateAndRetrieveFields(doc)
	if err != nil {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Rename the offending field in the chaincode value, e.g. from 'version' to 'docVersion' or '_rev' to 'rev'
  2. Strip underscore-prefixed metadata fields from the JSON before calling PutState
  3. Add a serialization layer in the chaincode that sanitizes keys before writing state

Example fix

// before
value := map[string]interface{}{"version": "v1", "_rev": "1-abc"}
jsonBytes, _ := json.Marshal(value)
stub.PutState(key, jsonBytes)
// after
value := map[string]interface{}{"docVersion": "v1", "rev": "1-abc"}
jsonBytes, _ := json.Marshal(value)
stub.PutState(key, jsonBytes)
Defensive patterns

Strategy: validation

Validate before calling

func safeForCouchState(v map[string]interface{}) error {
    for k := range v {
        if k == "version" || strings.HasPrefix(k, "_") {
            return fmt.Errorf("field [%s] not allowed in state JSON", k)
        }
    }
    return nil
}

Type guard

func hasReservedFields(v map[string]interface{}) bool {
    for k := range v {
        if k == "version" || strings.HasPrefix(k, "_") { return true }
    }
    return false
}

Prevention

When it happens

Trigger: A chaincode PutState writes a JSON value (via the value-hash or JSON state handling) whose key set includes 'version' or any '_'-prefixed key, and that value passes through jsonValue validation during commit validation.

Common situations: Porting application documents that already use CouchDB-style metadata (_id, _rev, _design) or a domain field literally named 'version' (document versioning schemas) directly into chaincode state without renaming the fields.

Related errors


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