{"record":{"id":"810a373f2892e19a","repo":"juicedata/juicefs","slug":"get-counter-s","errorCode":null,"errorMessage":"get counter %s","messagePattern":"get counter (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/redis_bak.go","lineNumber":70,"sourceCode":"\t\tm.dumpACL,\n\t\tm.dumpQuota,\n\t\tm.dumpDirStat,\n\t}\n\tfor _, f := range dumps {\n\t\terr := f(ctx, opt, ch)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (m *redisMeta) dumpCounters(ctx Context, opt *DumpOption, ch chan<- *dumpedResult) error {\n\tcounters := make([]*pb.Counter, 0, len(counterNames)+1)\n\tfor _, name := range counterNames {\n\t\tcnt, err := m.getCounter(name)\n\t\tif err != nil {\n\t\t\treturn errors.Wrapf(err, \"get counter %s\", name)\n\t\t}\n\t\tif name == \"nextInode\" || name == \"nextChunk\" {\n\t\t\tcnt++ // Redis nextInode/nextChunk is one smaller than db\n\t\t}\n\t\tcounters = append(counters, &pb.Counter{Key: name, Value: cnt})\n\t}\n\tif m.getFormat().ChangeLog {\n\t\tlastLog, err := m.rdb.Get(ctx, m.txnLastLog()).Int64()\n\t\tif err == nil {\n\t\t\tcounters = append(counters, &pb.Counter{Key: \"lastChangelog\", Value: lastLog})\n\t\t}\n\t}\n\treturn dumpResult(ctx, ch, &dumpedResult{msg: &pb.Batch{Counters: counters}})\n}\n\nfunc (m *redisMeta) dumpMix(ctx Context, opt *DumpOption, ch chan<- *dumpedResult) error {\n\tlogger.Warnf(\"please make sure the redis server is readonly, otherwise the dumped metadata will be inconsistent\")\n\tpools := map[int][]*sync.Pool{","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/redis_bak.go#L52-L88","documentation":"Raised by redisMeta.dumpCounters while dumping metadata: for each well-known counter (counterNames) the code calls m.getCounter(name), and any failure reading a counter from Redis is wrapped with \"get counter <name>\". DumpMeta needs all counters (usedInode, usedSpace, nextInode, nextChunk, etc.) to serialize a complete metadata image, so a read failure aborts the dump.","triggerScenarios":"Running `juicefs dump` or metadata backup on a Redis engine when getCounter (a Redis GET on the counter key) fails — connection error, cluster routing failure, or timeout — for one of the standard counters.","commonSituations":"Redis failover during a long dump; READONLY replica used for backup reads; flaky network to Redis on large clusters; missing counter keys after manual key deletion (depends on getCounter's handling of missing keys).","solutions":["Retry the dump once Redis connectivity is stable; counters are simple GETs and the failure is usually transient.","Confirm the Redis endpoint is a primary (or correctly routed cluster node), not a read-only replica.","Check the specific counter named in the message exists in the keyspace (redis-cli GET with the counter name).","Verify Redis health (latency, maxclients, OOM) if dumps repeatedly fail mid-way."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Confirm the Redis endpoint answers before starting a dump:\nif err := rdb.Ping(ctx).Err(); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := juicefs.Dump(ctx, meta, f, opt)\nfor attempt := 0; err != nil && strings.Contains(err.Error(), \"get counter\") && attempt < 3; attempt++ {\n    time.Sleep(backoff(attempt))\n    err = juicefs.Dump(ctx, meta, f, opt)\n}","preventionTips":["Dump from a stable Redis primary with verified connectivity.","Avoid running dumps during Redis failover or maintenance windows.","Verify counter keys exist if manual key operations were performed.","Schedule large dumps with generous client timeouts."],"tags":["go","redis","dump","counters"],"backgroundTag":"database-query-failed","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"}