{"record":{"id":"31077e95bc1e09e8","repo":"ory/hydra","slug":"could-not-cleanup-inactive-s","errorCode":null,"errorMessage":"Could not cleanup inactive %s","messagePattern":"Could not cleanup inactive (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cli/handler_janitor.go","lineNumber":176,"sourceCode":"\t\tswitch n {\n\t\tcase OnlyTokens:\n\t\t\troutines = append(routines, cleanup(out, p.FlushInactiveAccessTokens, \"access tokens\"))\n\t\t\troutines = append(routines, cleanup(out, p.FlushInactiveRefreshTokens, \"refresh tokens\"))\n\t\tcase OnlyRequests:\n\t\t\troutines = append(routines, cleanup(out, p.FlushInactiveLoginConsentRequests, \"login-consent requests\"))\n\t\tcase OnlyGrants:\n\t\t\troutines = append(routines, cleanup(out, p.FlushInactiveGrants, \"grants\"))\n\t\t}\n\t}\n\treturn routines\n}\n\ntype cleanupRoutine func(ctx context.Context, notAfter time.Time, limit int, batchSize int) error\n\nfunc cleanup(out io.Writer, cr cleanupRoutine, routineName string) cleanupRoutine {\n\treturn func(ctx context.Context, notAfter time.Time, limit int, batchSize int) error {\n\t\tif err := cr(ctx, notAfter, limit, batchSize); err != nil {\n\t\t\treturn errors.Wrap(errors.WithStack(err), fmt.Sprintf(\"Could not cleanup inactive %s\", routineName))\n\t\t}\n\t\t_, _ = fmt.Fprintf(out, \"Successfully completed Janitor run on %s\\n\", routineName)\n\t\treturn nil\n\t}\n}\n\nfunc cleanupRun(ctx context.Context, notAfter time.Time, limit int, batchSize int, routines ...cleanupRoutine) error {\n\tif len(routines) == 0 {\n\t\treturn errors.New(\"clean up run received 0 routines\")\n\t}\n\n\tfor _, r := range routines {\n\t\tif err := r(ctx, notAfter, limit, batchSize); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/cmd/cli/handler_janitor.go#L158-L194","documentation":"The janitor's cleanup() wrapper wraps errors from an inner cleanup routine (tables like jti, flow, access, refresh tokens) with the routine name, producing 'Could not cleanup inactive <name>'. The routineName identifies which table/kind of records the failing batch cleanup targets.","triggerScenarios":"Any janitor cleanup routine (e.g. cleanupFlow, cleanupJTI) returning an error while deleting expired records in batches — database connectivity loss mid-run, SQL constraint errors, or context cancellation during a long batched delete.","commonSituations":"Database connection dropped during a long janitor run on a large table; lock timeouts while the database is under load; batch size too large causing statement timeouts; migrations missing so the table being cleaned doesn't exist.","solutions":["Read the wrapped cause (printed via stack trace) to identify the SQL-level failure.","Re-run janitor after verifying database connectivity; janitor is idempotent so partially cleaned data is fine.","Reduce --cleanup-batch-size if statement timeouts occur on very large tables.","Ensure migrations are fully applied (hydra migrate sql up) so the target tables exist."],"exampleFix":"// before\nhydra janitor -e \"$DSN\" --cleanup-batch-size 1000000\n\n// after\nhydra migrate sql up -e \"$DSN\"\nhydra janitor -e \"$DSN\" --cleanup-batch-size 100 --cleanup-grace-period 24h","handlingStrategy":"retry","validationCode":"if err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"database unreachable before janitor run: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := janitor.Run(ctx)\nif err != nil {\n    if errors.Is(err, context.Canceled) || isTransientDBError(err) {\n        // janitor is idempotent; safe to retry with backoff\n        time.Sleep(backoff)\n        return janitor.Run(ctx)\n    }\n    log.Fatalf(\"janitor failed: %+v\", err)\n}","preventionTips":["Use a modest --cleanup-batch-size (e.g. 100) to avoid statement timeouts on large tables.","Schedule janitor runs off-peak to reduce lock contention.","Run `hydra migrate sql up` before the first janitor run against a new database.","Set generous DB timeouts/connection pool settings for long cleanup runs."],"tags":["cli","database","janitor","cleanup","batch-delete"],"backgroundTag":"database-query-failed","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}