t8y2/dbx · error
invalid lease continuation: %s
Error message
invalid lease continuation: %s
What it means
parseUnsignedLong parses the continuation token used to page through leases into a uint64. If the token string is not a valid base-10 unsigned 64-bit integer, it fails with this error. The continuation value is expected to be a raw lease ID emitted by a previous leaseList page, so this error means the token is malformed or was never a lease ID.
Source
Thrown at agents/drivers/etcd-go/lease.go:181
var errLeaseListDeadline = errors.New("ETCD_LEASE_LIST_TIMEOUT")
func isDeadlineError(err error) bool {
return errors.Is(err, context.DeadlineExceeded) || status.Code(err) == codes.DeadlineExceeded
}
func isLeaseListFallbackError(err error) bool {
if errors.Is(err, errLeaseListDeadline) || errors.Is(err, context.DeadlineExceeded) {
return true
}
code := status.Code(err)
return code == codes.Unimplemented || code == codes.DeadlineExceeded
}
func parseUnsignedLong(value string) (uint64, error) {
parsed, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid lease continuation: %s", value)
}
return parsed, nil
}
func leasePageIDs(leaseIDs []uint64, afterLeaseID *uint64, fetchLimit int) []uint64 {
sorted := make([]uint64, len(leaseIDs))
copy(sorted, leaseIDs)
sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] })
result := []uint64{}
for _, id := range sorted {
if afterLeaseID != nil && id <= *afterLeaseID {
continue
}
if len(result) >= fetchLimit {
break
}
result = append(result, id)
}View on GitHub (pinned to c0390bff16)
Solutions
- Pass back the continuation token exactly as returned by the previous leaseList page, unmodified.
- If constructing manually, supply a decimal string of a uint64 lease ID (e.g. "7587868030128843137").
- Strip any URL-encoding, quotes, or whitespace before parsing; base64-decode only if your wrapper layer encoded it.
- Restart pagination without a continuation token to fetch the first page, then resume with the fresh token.
Example fix
// before
parseUnsignedLong("page-2") // not a uint64
// after
parseUnsignedLong("7587868030128843137") // lease ID from previous page Defensive patterns
Strategy: validation
Validate before calling
func validContinuation(token string) bool {
if token == "" {
return false
}
_, err := strconv.ParseUint(token, 10, 64)
return err == nil
}
// if afterLeaseID != "" && !validContinuation(afterLeaseID) { reject before calling leaseList } Try / catch
resp, err := driver.LeaseList(continuation)
if err != nil {
if strings.HasPrefix(err.Error(), "invalid lease continuation") {
// token unusable: restart pagination from the first page
resp, err = driver.LeaseList("")
}
if err != nil {
return err
}
} Prevention
- Treat continuation tokens as opaque; echo back exactly what the server returned.
- Store tokens in lossless containers (strings in JSON, not numbers that can overflow or reformat).
- Avoid URL-encoding or wrapping tokens in envelopes that add prefixes/suffixes.
- Don't mix pagination tokens between drivers or endpoints.
When it happens
Trigger: leaseList called with an afterLeaseID/continuation string that is empty, contains non-digit characters, has a sign or decimal point, exceeds uint64 range, or is an opaque/op-echo token from a different API.
Common situations: Client stored the continuation as a JSON object or base64 and passed the whole blob back; truncation/URL-encoding corrupted the token; passing a key or revision instead of a lease ID as the continuation; cross-driver paging tokens mixed up.
Related errors
- ETCD_LEASE_LIST_TIMEOUT
- lease, ttl, and preserveLease cannot be specified together
- ttl must be a positive integer
- Cannot preserve lease: key does not exist or has no lease
- Cannot preserve lease: key changed concurrently; retry the s
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/3fb5fb6692fefe36.
Report an issue: GitHub.