hyperledger/fabric · error

the BlockToLive in an existing collection [%s] modified. Exi

Error message

the BlockToLive in an existing collection [%s] modified. Existing value [%d]

What it means

Hyperledger Fabric's lifecycle SCC rejects any attempt to modify the BlockToLive field of an already-committed private data collection. Once a collection is committed, BlockToLive is immutable; validateCollConfigsAgainstCommittedDef compares the proposed collection against the committed definition and fails when the values differ. The committed (existing) value is reported in the message.

Source

Thrown at core/chaincode/lifecycle/scc.go:952

		proposedCollsMap[c.Name] = c
	}

	// In the new collection config package, ensure that there is one entry per old collection. Any
	// number of new collections are allowed.
	for _, committedCollConfig := range committedCollConfPkg.Config {
		committedColl := committedCollConfig.GetStaticCollectionConfig()
		// It cannot be nil
		if committedColl == nil {
			return errors.Errorf("unknown collection configuration type")
		}

		newCollection, ok := proposedCollsMap[committedColl.Name]
		if !ok {
			return errors.Errorf("existing collection [%s] missing in the proposed collection configuration", committedColl.Name)
		}

		if newCollection.BlockToLive != committedColl.BlockToLive {
			return errors.Errorf("the BlockToLive in an existing collection [%s] modified. Existing value [%d]", committedColl.Name, committedColl.BlockToLive)
		}
	}
	return nil
}

func (i *Invocation) createOpaqueStates() ([]OpaqueState, error) {
	if i.ApplicationConfig == nil {
		return nil, errors.Errorf("no application config for channel '%s'", i.Stub.GetChannelID())
	}
	orgs := i.ApplicationConfig.Organizations()
	opaqueStates := make([]OpaqueState, 0, len(orgs))
	for _, org := range orgs {
		opaqueStates = append(opaqueStates, &ChaincodePrivateLedgerShim{
			Collection: implicitcollection.NameForOrg(org.MSPID()),
			Stub:       i.Stub,
		})
	}
	return opaqueStates, nil

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Restore the BlockToLive value in the proposed config to match the committed value exactly (the existing value is printed in the error message)
  2. Retrieve the committed collection config (QSCC GetChaincodeCollectionConfig or QueryChaincodeDefinition) and base edits on it
  3. If retention must change, create a new collection with a new name (data migration) instead of mutating the existing one
  4. Use the peer's pre-check via CheckCommitReadiness to validate the update before committing

Example fix

// before (collections_config.json)
{"name":"coll1","blockToLive":0}
// after
{"name":"coll1","blockToLive":100000}  // must equal committed value
Defensive patterns

Strategy: validation

Validate before calling

// compare proposed vs committed before submitting update
committed, _ := getCommittedCollectionConfig(channel, ccName)
for _, proposed := range proposedColls {
  for _, c := range committed {
    if c.Name == proposed.Name && c.BlockToLive != proposed.BlockToLive {
      return fmt.Errorf("BlockToLive for %s is immutable (committed=%d)", c.Name, c.BlockToLive)
    }
  }
}

Type guard

func blockToLiveUnchanged(committed, proposed uint64) bool { return committed == proposed }

Prevention

When it happens

Trigger: Calling _commitUpdateCollectionConfig (via chaincode Invoke on the _lifecycle SCC, e.g. through CommitChaincodeDefinition or a collection-config update transaction) with a CollectionConfigPackage where a collection with the same name has a different BlockToLive than the one on the ledger.

Common situations: Operators editing a collections_config.json to tighten or extend private data retention (e.g. changing BlockToLive from 100000 to 0 or a larger value) and redeploying; CLI tooling regenerating collection configs with different defaults; SDKs re-submitting configs where BlockToLive was changed to try to expire old private data.

Related errors


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