juicedata/juicefs · error

invalid key , fail to parse timestamp

Error message

invalid key %s, fail to parse timestamp

What it means

Companion to the previous check: the key split into two parts, but the second part (the timestamp that decides when delayed deletions become eligible for cleanup) is not a valid base-10 integer. Cleanup aborts because it cannot decide whether the slices are due for deletion.

Solutions

  1. Print the key (it is included in the error) and inspect the actual hash entry with redis-cli.
  2. Fix or remove the malformed key if its data is not needed, then re-run cleanup.
  3. Audit what writes into the delSlices hash — ensure no other app or old client shares this Redis DB.
  4. Restore affected hash entries from a known-good metadata backup if corruption is widespread.
Defensive patterns

Strategy: validation

Validate before calling

for _, k := range hashKeys {
    ps := strings.Split(k, "_")
    if len(ps) == 2 { if _, err := strconv.ParseInt(ps[1], 10, 64); err != nil { fmt.Printf("bad timestamp in key %q\n", k) } }
}

Try / catch

if err := cleanup(ctx); err != nil && strings.Contains(err.Error(), "fail to parse timestamp") {
    logger.Errorf("corrupt delSlices key: %v", err)
    // remove or repair the specific key reported, then re-run
}

Prevention

When it happens

Trigger: A delSlices hash key like "12345_notanumber" — produced by manual edits, corrupted metadata, or a mismatched writer — encountered while parsing the timestamp portion during delayed-slice cleanup.

Common situations: Hand-edited Redis keys; partially restored backups; another application writing colliding keys into the same hash.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/68b824ef8d88984b. Report an issue: GitHub.

Appendix: source

Thrown at pkg/meta/redis.go:4120

	var rs []*redis.IntCmd
	for key := range delKeys {
		var clean bool
		task := func(tx *redis.Tx) error {
			ss = ss[:0]
			rs = rs[:0]
			val, err := tx.HGet(ctx, m.delSlices(), key).Result()
			if err == redis.Nil {
				return nil
			} else if err != nil {
				return err
			}
			ps := strings.Split(key, "_")
			if len(ps) != 2 {
				return fmt.Errorf("invalid key %s", key)
			}
			ts, err := strconv.ParseInt(ps[1], 10, 64)
			if err != nil {
				return fmt.Errorf("invalid key %s, fail to parse timestamp", key)
			}

			m.decodeDelayedSlices([]byte(val), &ss)
			clean, err = scan(ss, ts)
			if err != nil {
				return err
			}
			if clean {
				_, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
					for _, s := range ss {
						rs = append(rs, pipe.HIncrBy(ctx, m.sliceRefs(), m.sliceKey(s.Id, s.Size), -1))
					}
					pipe.HDel(ctx, m.delSlices(), key)
					id, err := strconv.ParseUint(ps[0], 10, 64)
					if err != nil {
						return fmt.Errorf("invalid key %s, fail to parse slice id", key)
					}
					m.genLog(ctx, pipe, time.Now(), "CLEANUP_TRASH_SLICES(%d,%d)", id, ts)

View on GitHub (pinned to c9a67b23e8)