{"record":{"id":"6c1fec0dd2dda5f1","repo":"juicedata/juicefs","slug":"prefix-must-be-nil-but-got-v","errorCode":null,"errorMessage":"prefix must be nil, but got %v","messagePattern":"prefix must be nil, but got (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/tkv_prefix.go","lineNumber":120,"sourceCode":"\nfunc (c *prefixClient) txn(ctx context.Context, f func(*kvTxn) error, retry int) error {\n\treturn c.tkvClient.txn(ctx, func(tx *kvTxn) error {\n\t\treturn f(&kvTxn{&prefixTxn{tx, c.prefix}, retry})\n\t}, retry)\n}\n\nfunc (c *prefixClient) scan(prefix []byte, handler func(key, value []byte) bool) error {\n\tk := make([]byte, len(c.prefix)+len(prefix))\n\tcopy(k, c.prefix)\n\tcopy(k[len(c.prefix):], prefix)\n\treturn c.tkvClient.scan(k, func(key, value []byte) bool {\n\t\treturn handler(key[len(c.prefix):], value)\n\t})\n}\n\nfunc (c *prefixClient) reset(prefix []byte) error {\n\tif prefix != nil {\n\t\treturn fmt.Errorf(\"prefix must be nil, but got %v\", prefix)\n\t}\n\treturn c.tkvClient.reset(c.prefix)\n}\n\nfunc (c *prefixClient) logKey(m *kvMeta, id uint64) []byte {\n\tif cc, ok := c.tkvClient.(tkvChangelogClient); ok {\n\t\treturn cc.logKey(m, id)\n\t}\n\treturn m.fmtKey(\"XLOG\", id)\n}\n\nfunc (c *prefixClient) scanLogRange(m *kvMeta, tx *kvTxn, beginID, endID uint64, keysOnly bool, handler func(id uint64, k, v []byte) bool) {\n\tif cc, ok := c.tkvClient.(tkvChangelogClient); ok {\n\t\tcc.scanLogRange(m, tx, beginID, endID, keysOnly, handler)\n\t\treturn\n\t}\n\ttx.scan(m.fmtKey(\"XLOG\", beginID), m.fmtKey(\"XLOG\", endID), keysOnly, func(k, v []byte) bool {\n\t\treturn handler(binary.BigEndian.Uint64(k[4:]), k, v)","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/tkv_prefix.go#L102-L138","documentation":"prefixClient wraps a tkvClient and scopes all keys under a prefix. Its reset() intentionally only accepts nil: the wrapper always resets the whole underlying client using its own prefix, so passing a non-nil prefix is treated as an API misuse and rejected with this error.","triggerScenarios":"Calling reset(somePrefix) on a *prefixClient obtained from tkv_prefix.go (e.g. in tests or engine glue) instead of reset(nil).","commonSituations":"Test helpers that share a reset helper across raw tkv clients and prefix-wrapped clients; code migrated from a raw tkvClient that still passes a prefix argument.","solutions":["Call reset(nil) on the prefixClient — the wrapper applies its own prefix to the underlying reset","If you need to reset a sub-range, reset the raw underlying tkvClient with that prefix instead of the wrapper","Fix shared test reset helpers to special-case prefixClient (or type-assert to it) and always pass nil"],"exampleFix":"// before\nerr := prefixCli.reset([]byte(\"test/\"))\n// after\nerr := prefixCli.reset(nil)","handlingStrategy":"validation","validationCode":"if pfx, ok := cli.(interface{ reset([]byte) error }); ok { _ = pfx.reset(nil) } // prefixClient.reset only accepts nil","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always call reset(nil) on prefixClient instances","Document reset semantics for wrapped clients in shared test helpers","Type-check client wrappers before reusing raw-engine reset helpers"],"tags":["api-misuse","prefix","testing"],"backgroundTag":"invalid-argument-value","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}