hyperledger/fabric · error
failed to unmarshal savepoint data
Error message
failed to unmarshal savepoint data
What it means
decodeSavepoint parses the stored savepoint JSON document back into a version.Height. If json.Unmarshal fails, the error is wrapped with 'failed to unmarshal savepoint data' and GetLatestSavePoint fails. This indicates the saved savepoint document in CouchDB is corrupt or in an unexpected format.
Source
Thrown at core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go:223
func encodeSavepoint(height *version.Height) (*couchDoc, error) {
var err error
var savepointDoc couchSavepointData
// construct savepoint document
savepointDoc.BlockNum = height.BlockNum
savepointDoc.TxNum = height.TxNum
savepointDocJSON, err := json.Marshal(savepointDoc)
if err != nil {
err = errors.Wrap(err, "failed to marshal savepoint data")
logger.Errorf("%+v", err)
return nil, err
}
return &couchDoc{jsonValue: savepointDocJSON, attachments: nil}, nil
}
func decodeSavepoint(couchDoc *couchDoc) (*version.Height, error) {
savepointDoc := &couchSavepointData{}
if err := json.Unmarshal(couchDoc.jsonValue, &savepointDoc); err != nil {
err = errors.Wrap(err, "failed to unmarshal savepoint data")
logger.Errorf("%+v", err)
return nil, err
}
return &version.Height{BlockNum: savepointDoc.BlockNum, TxNum: savepointDoc.TxNum}, nil
}
func encodeChannelMetadata(metadataDoc *channelMetadata) (*couchDoc, error) {
metadataJSON, err := json.Marshal(metadataDoc)
if err != nil {
err = errors.Wrap(err, "failed to marshal channel metadata")
logger.Errorf("%+v", err)
return nil, err
}
return &couchDoc{jsonValue: metadataJSON, attachments: nil}, nil
}
func decodeChannelMetadata(couchDoc *couchDoc) (*channelMetadata, error) {
metadataDoc := &channelMetadata{}View on GitHub (pinned to 2736b63f8f)
Solutions
- Inspect the savepoint document in CouchDB; restore it to valid JSON with BlockNum and TxNum fields
- Restore the state database from a known-good backup
- If the ledger is unusable, drop and rebuild the ledger database (full re-sync from the blockchain/orderer)
Example fix
// before (corrupt doc)
{"BlockNum": "not-a-number"}
// after
{"BlockNum": 100, "TxNum": 0} Defensive patterns
Strategy: try-catch
Validate before calling
func validSavepointJSON(b []byte) bool {
var d struct{ BlockNum uint64; TxNum uint64 }
return json.Unmarshal(b, &d) == nil
} Try / catch
h, err := decodeSavepoint(doc)
if err != nil {
return nil, fmt.Errorf("savepoint document corrupt, restore from backup: %w", err)
} Prevention
- Do not modify internal savepoint documents in CouchDB
- Take consistent full backups of the state database
- Restrict CouchDB admin access to ledger databases
When it happens
Trigger: GetLatestSavePoint reads the savepoint document from CouchDB and the jsonValue bytes cannot be unmarshaled into couchSavepointData (corrupt bytes, wrong document type, truncated JSON).
Common situations: Manual edits to the CouchDB savepoint document, database corruption, restoring CouchDB from an incompatible backup, or another application overwriting the savepoint doc in the ledger's database.
Related errors
- failed to unmarshal channel metadata
- failed to unmarshal json [%#v] into dataformatInfo
- error marshalling json data
- failed to marshal savepoint data
- too few arguments
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f6feb8336e1fe2ae.
Report an issue: GitHub.