{"record":{"id":"62afd7eba1f19237","repo":"juicedata/juicefs","slug":"failed-to-clean-up-sid-d","errorCode":null,"errorMessage":"failed to clean up sid %d","messagePattern":"failed to clean up sid (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/redis.go","lineNumber":2966,"sourceCode":"\t\tfail = true\n\t}\n\n\tkey = m.sustained(sid)\n\tif inodes, err := m.rdb.SMembers(ctx, key).Result(); err == nil {\n\t\tfor _, sinode := range inodes {\n\t\t\tinode, _ := strconv.ParseUint(sinode, 10, 64)\n\t\t\tif err = m.doDeleteSustainedInode(sid, Ino(inode)); err != nil {\n\t\t\t\tlogger.Warnf(\"Delete sustained inode %d of sid %d: %s\", inode, sid, err)\n\t\t\t\tfail = true\n\t\t\t}\n\t\t}\n\t} else {\n\t\tlogger.Warnf(\"SMembers %s: %s\", key, err)\n\t\tfail = true\n\t}\n\n\tif fail {\n\t\treturn fmt.Errorf(\"failed to clean up sid %d\", sid)\n\t} else {\n\t\tvar removed *redis.IntCmd\n\t\tif _, err := m.rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error {\n\t\t\tpipe.HDel(ctx, m.sessionInfos(), ssid)\n\t\t\tremoved = pipe.ZRem(ctx, m.allSessions(), ssid)\n\t\t\tm.genLog(ctx, pipe, time.Now(), \"CLEANSESSION(%d)\", sid)\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif n, err := removed.Result(); err != nil {\n\t\t\treturn err\n\t\t} else if n == 1 {\n\t\t\treturn nil\n\t\t}\n\t\treturn m.rdb.ZRem(ctx, legacySessions, ssid).Err()\n\t}\n}","sourceCodeStart":2948,"sourceCodeEnd":2984,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/redis.go#L2948-L2984","documentation":"When cleaning up a client session (by sid), redisMeta first removes the session's locks/ftype entries. If any of those sub-steps fails (it sets fail=true and logs e.g. 'SMembers %s: %s'), it aborts and returns this error instead of half-cleaning the session. The session record itself is left in place so the cleanup can be retried later.","triggerScenarios":"Calling session cleanup (e.g. `juicefs status`/stale session GC path that ends in CLEANSESSION) when SMembers/HDEL on the session's lock or ftype keys fails, or the deliberately failing probe path detects a partial cleanup.","commonSituations":"Redis connection instability during session GC; removing a dead client's session while a replica failover is in progress; ACL restrictions preventing reads of session sub-keys.","solutions":["Read the preceding Warnf log line (e.g. 'SMembers ...: <err>') to find which sub-step failed and fix that Redis error.","Retry the session cleanup once Redis is healthy; the operation is designed to be safe to re-run.","If the session is truly dead and cleanup keeps failing, manually remove the session keys (sessionInfo hash entry and allSessions zset member) during a maintenance window.","Check Redis ACLs allow reads/writes on the session-related keys."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if err := rdb.Ping(ctx).Err(); err != nil { return err } // ensure redis is healthy before session GC","typeGuard":null,"tryCatchPattern":"if err := cleanSession(ctx, sid); err != nil && strings.Contains(err.Error(), \"failed to clean up sid\") {\n    logger.Warnf(\"session %d cleanup deferred, will retry\", sid)\n    scheduleRetry(sid, 5*time.Minute)\n}","preventionTips":["Run stale-session cleanup on a schedule against a healthy Redis","Check the JuiceFS warn log for the underlying SMembers/HDEL error before intervening","Don't share the metadata Redis instance with unrelated workloads"],"tags":["redis","session","cleanup","partial-failure"],"backgroundTag":"database-write-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"}