{"record":{"id":"5ebca3f58ba4381e","repo":"hyperledger/fabric","slug":"failed-to-marshal-savepoint-data","errorCode":null,"errorMessage":"failed to marshal savepoint data","messagePattern":"failed to marshal savepoint data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go","lineNumber":213,"sourceCode":"\tChannelName string `json:\"ChannelName\"`\n\t// namespace to namespaceDBInfo mapping\n\tNamespaceDBsInfo map[string]*namespaceDBInfo `json:\"NamespaceDBsInfo\"`\n}\n\ntype namespaceDBInfo struct {\n\tNamespace string `json:\"Namespace\"`\n\tDBName    string `json:\"DBName\"`\n}\n\nfunc encodeSavepoint(height *version.Height) (*couchDoc, error) {\n\tvar err error\n\tvar savepointDoc couchSavepointData\n\t// construct savepoint document\n\tsavepointDoc.BlockNum = height.BlockNum\n\tsavepointDoc.TxNum = height.TxNum\n\tsavepointDocJSON, err := json.Marshal(savepointDoc)\n\tif err != nil {\n\t\terr = errors.Wrap(err, \"failed to marshal savepoint data\")\n\t\tlogger.Errorf(\"%+v\", err)\n\t\treturn nil, err\n\t}\n\treturn &couchDoc{jsonValue: savepointDocJSON, attachments: nil}, nil\n}\n\nfunc decodeSavepoint(couchDoc *couchDoc) (*version.Height, error) {\n\tsavepointDoc := &couchSavepointData{}\n\tif err := json.Unmarshal(couchDoc.jsonValue, &savepointDoc); err != nil {\n\t\terr = errors.Wrap(err, \"failed to unmarshal savepoint data\")\n\t\tlogger.Errorf(\"%+v\", err)\n\t\treturn nil, err\n\t}\n\treturn &version.Height{BlockNum: savepointDoc.BlockNum, TxNum: savepointDoc.TxNum}, nil\n}\n\nfunc encodeChannelMetadata(metadataDoc *channelMetadata) (*couchDoc, error) {\n\tmetadataJSON, err := json.Marshal(metadataDoc)","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/ledger/kvledger/txmgmt/statedb/statecouchdb/couchdoc_conv.go#L195-L231","documentation":"encodeSavepoint serializes couchSavepointData (block and tx number) to JSON for persisting the ledger's latest savepoint in CouchDB. Failures are wrapped with 'failed to marshal savepoint data'. With plain uint64 fields this essentially cannot fail unless the struct or JSON library behaves abnormally.","triggerScenarios":"recordSavepoint calls encodeSavepoint and json.Marshal returns an error while constructing the savepoint document for the given height.","commonSituations":"Custom builds where couchSavepointData gained non-JSON-serializable fields (channels, funcs, cycles), or corrupted dependencies/JSON library behavior.","solutions":["Read the wrapped cause from the Errorf log to identify the failing field in couchSavepointData","Ensure couchSavepointData contains only JSON-serializable primitive fields","Retry the commit; if persistent, rebuild the peer binary from a stock Fabric release"],"exampleFix":"// before\ntype couchSavepointData struct {\n    BlockNum uint64\n    Conn chan struct{} // not serializable\n}\n// after\ntype couchSavepointData struct {\n    BlockNum uint64\n    TxNum    uint64\n}","handlingStrategy":"try-catch","validationCode":"if _, err := json.Marshal(savepointDoc); err != nil {\n    return fmt.Errorf(\"savepoint doc not serializable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"doc, err := encodeSavepoint(height)\nif err != nil {\n    logger.Errorf(\"savepoint encode failed: %+v\", err)\n    return err\n}","preventionTips":["Keep couchSavepointData limited to primitive fields","Rebuild peers from stock Fabric sources","Log the wrapped cause with %+v for diagnosis"],"tags":["json","marshalling","savepoint","fabric-ledger"],"backgroundTag":"json-marshalling-failed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}