hyperledger/fabric · error

nil version not supported

Error message

nil version not supported

What it means

encodeVersionAndMetadata serializes a version.Height into the CouchDB value envelope. It refuses a nil version because a stored state entry must carry block/tx provenance; a nil version would produce an unusable record that cannot be reconstructed during reads.

Source

Thrown at core/ledger/kvledger/txmgmt/statedb/statecouchdb/dbvalue_encoding.go:19

/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package statecouchdb

import (
	"encoding/base64"

	"github.com/hyperledger/fabric/core/ledger/internal/version"
	"github.com/pkg/errors"
	"google.golang.org/protobuf/proto"
)

func encodeVersionAndMetadata(version *version.Height, metadata []byte) (string, error) {
	if version == nil {
		return "", errors.New("nil version not supported")
	}
	msg := &VersionAndMetadata{
		Version:  version.ToBytes(),
		Metadata: metadata,
	}
	msgBytes, err := proto.Marshal(msg)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(msgBytes), nil
}

func decodeVersionAndMetadata(encodedstr string) (*version.Height, []byte, error) {
	persistedVersionAndMetadata, err := base64.StdEncoding.DecodeString(encodedstr)
	if err != nil {
		return nil, nil, err
	}
	versionAndMetadata := &VersionAndMetadata{}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Pass a valid *version.Height (from the committing block's Height) instead of nil.
  2. When constructing VersionedValue manually, set version via version.NewHeight(blockNum, txNum).
  3. Trace where the nil version originates — usually the caller of PutValAndMetadata or a batch builder — and supply the current block height.
  4. If this is pure metadata-only data, use an API path that does not require versioning.

Example fix

// before
batch.PutValAndMetadata(ns, key, value, metadata, nil)
// after
ver := version.NewHeight(blockNum, txNum)
batch.PutValAndMetadata(ns, key, value, metadata, ver)
Defensive patterns

Strategy: type-guard

Validate before calling

if version == nil {
  return fmt.Errorf("cannot persist key %s: version is nil; supply version.NewHeight(blockNum, txNum)", key)
}

Type guard

func hasVersion(vv *statedb.VersionedValue) bool {
  return vv != nil && vv.Version != nil
}

Prevention

When it happens

Trigger: keyValToCouchDoc encoding a VersionedValue whose Version field is nil — e.g. a batch entry built with a nil *version.Height, or code paths that insert values without a block height context (also hit directly in the encode/decode unit test).

Common situations: Custom batch construction in tests or tooling that forgets to set Version; calling internal serialization helpers outside the normal commit flow where the version is computed from the block height.

Related errors


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