juicedata/juicefs · error
get range
Error message
get range [%v-%v): %s
What it means
`etcdTxn.scan` reads a half-open key range [begin, end) from etcd; if the range Get RPC fails the transaction panics with this message naming the range. Scans power directory listing and other range reads in the TKV metadata layer.
Solutions
- Run `etcdctl endpoint health` and check etcd logs for the failing range request
- Fix connectivity/auth (endpoints, certificates, user permissions on the key range)
- Retry the listing after transient etcd issues; increase client timeout for large directories
- Keep directories reasonably sized or shard keys if scans routinely time out
Defensive patterns
Strategy: retry
Validate before calling
etcdctl --endpoints=host:2379 endpoint health && etcdctl auth status
Try / catch
if err := listDir(); err != nil {
if isTransient(err) { time.Sleep(backoff); listDir() } else { return err }
} Prevention
- Verify etcd user has read permission on the volume's key prefix
- Avoid giant directories when clients sit far from etcd
- Keep etcd compacted/defragmented and monitored
- Pin client timeouts generously for large scans
When it happens
Trigger: Listing a directory or scanning metadata keys in an etcd-backed volume when the etcd range query errors: unreachable endpoint, auth revoked, context deadline exceeded, etcd compaction/leader change mid-request.
Common situations: etcd overloaded by large directory scans; network flakiness; expired etcd user credentials/token; request timeout on huge directories over slow links.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/aa58e2aa4bd04837.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/meta/tkv_etcd.go:117
values[i] = v
continue
}
values[i] = rs[k]
if len(values[i]) == 0 {
tx.observed[k] = 0
}
}
return values
}
func (tx *etcdTxn) scan(begin, end []byte, keysOnly bool, handler func(k, v []byte) bool) {
opts := []etcd.OpOption{etcd.WithRange(string(end))}
if keysOnly {
opts = append(opts, etcd.WithKeysOnly())
}
resp, err := tx.kv.Get(tx.ctx, string(begin), opts...)
if err != nil {
panic(fmt.Errorf("get range [%v-%v): %s", string(begin), string(end), err))
}
for _, kv := range resp.Kvs {
tx.observed[string(kv.Key)] = kv.ModRevision
if !handler(kv.Key, kv.Value) {
break
}
}
}
func (tx *etcdTxn) exist(prefix []byte) bool {
resp, err := tx.kv.Get(tx.ctx, string(prefix), etcd.WithPrefix(), etcd.WithCountOnly())
if err != nil {
panic(fmt.Errorf("get prefix %v with count only: %s", string(prefix), err))
}
return resp.Count > 0
}
func (tx *etcdTxn) set(key, value []byte) {View on GitHub (pinned to c9a67b23e8)