{"record":{"id":"a9cf8c64887f871f","repo":"juicedata/juicefs","slug":"panic-in-point-get-transaction-v","errorCode":null,"errorMessage":"panic in point get transaction: %v","messagePattern":"panic in point get transaction: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/tkv_tikv.go","lineNumber":345,"sourceCode":"\t\t\tlogger.Warnf(\"TiKV get startTS: %s\", err)\n\t\t\treturn nil\n\t\t}\n\t\treturn ts\n\t}\n\treturn nil\n}\n\nfunc (c *tikvClient) simpleTxn(ctx context.Context, f func(*kvTxn) error, retry int) (err error) {\n\ttx, err := c.client.Begin(tikv.WithStartTS(math.MaxUint64)) // math.MaxUint64 means to point get the latest committed data without PD access\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"failed to begin transaction\")\n\t}\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif e, ok := r.(error); ok {\n\t\t\t\terr = e\n\t\t\t} else {\n\t\t\t\terr = errors.Errorf(\"panic in point get transaction: %v\", r)\n\t\t\t}\n\t\t}\n\t}()\n\tif err = f(&kvTxn{&tikvTxn{tx}, retry}); err != nil {\n\t\treturn err\n\t}\n\tif !tx.IsReadOnly() {\n\t\treturn syscall.EINVAL\n\t}\n\treturn nil\n}\n\nfunc (c *tikvClient) txn(ctx context.Context, f func(*kvTxn) error, retry int) (err error) {\n\tvar opts []tikv.TxnOption\n\tif val := ctx.Value(txSessionKey{}); val != nil {\n\t\topts = append(opts, tikv.WithStartTS(val.(uint64)))\n\t}\n","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/tkv_tikv.go#L327-L363","documentation":"In tikvClient.simpleTxn (pkg/meta/tkv_tikv.go:345), the deferred recover() converts a panic raised while executing the point-get callback f into \"panic in point get transaction: %v\" (passing it through unchanged if it is already an error). It guards metadata reads against panics inside the TiKV transaction body.","triggerScenarios":"A point-get via simpleTxn panics inside the kvTxn callback: nil key/value handling on malformed records, decode errors on unexpected value formats, or lower-level tikv-client-go panics (e.g. on region errors during raw scans).","commonSituations":"Metadata values written by a different (incompatible) JuiceFS version or corrupted in the TiKV store; tikv-client-go internal bugs triggered by region merges/splits mid-read; manual edits of the TiKV data.","solutions":["Capture the stack trace printed by debug.PrintStack in the client log and identify which decode/scan panicked.","Run `juicefs fsck` against the volume to find corrupt or incompatible metadata entries and repair/remove them.","Align JuiceFS client and TiKV cluster versions (upgrade tikv-client-go via a newer JuiceFS release) and retry; restore from a metadata backup if records are irrecoverably corrupt."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-flight: verify metadata integrity\n// juicefs fsck tikv://pd:2379/volume","typeGuard":null,"tryCatchPattern":"if err := doMetaOp(); err != nil {\n    if strings.HasPrefix(err.Error(), \"panic in point get transaction:\") {\n        // inspect the printed stack, fsck the volume, align client/TiKV versions\n    }\n}","preventionTips":["Never hand-edit TiKV metadata values; only write through JuiceFS.","Run `juicefs fsck` to detect corrupt/incompatible records after unexpected crashes.","Keep JuiceFS (and its embedded tikv-client-go) updated to match the server cluster version."],"tags":["go","tikv","panic","point-get","recovery"],"backgroundTag":"internal-invariant-violation","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}