kopia/kopia · warning
unable to run maintenance
Error message
unable to run maintenance
What it means
The server's periodic maintenance task wraps repo.DirectWriteSession + snapshotmaintenance.Run in a taskmgr task; any failure is wrapped as 'unable to run maintenance'. Maintenance handles garbage collection, blob retention, and content rewriting, so failures here can let deleted data accumulate but don't corrupt existing snapshots.
Solutions
- Check the wrapped error for lock contention and ensure no other client is running maintenance at the same interval.
- Run `kopia maintenance run` manually on one designated client to see and fix the underlying error.
- Verify the storage backend is writable and not rate-limiting during maintenance operations.
- Increase maintenance scheduling interval or ensure the server stays up long enough for full maintenance to finish.
Example fix
// before // two hosts both run auto maintenance -> lock contention // after // on secondary clients: kopia maintenance set-owner --maybe-perform-quick-maintenance=false <client-id> // keep periodic maintenance on the server host only
Defensive patterns
Strategy: retry
Try / catch
err := s.runMaintenanceTask(ctx, dr)
if err != nil {
// lock contention is transient: reschedule rather than fail hard
if strings.Contains(err.Error(), "unable to obtain lock") { scheduleRetry() }
} Prevention
- Designate a single maintenance owner (maintenance set-owner) to avoid contention
- Schedule maintenance during idle windows and keep the server alive long enough to finish
- Ensure the storage backend is writable and not rate-limited during maintenance
When it happens
Trigger: DirectWriteSession cannot get a write lock on the repository (another client holds it); maintenance run by another client conflicts; underlying storage errors during GC/rewrite; context cancellation when the server shuts down mid-run.
Common situations: Another host/client is running maintenance simultaneously (exclusive lock contention); read-only storage backend; blob storage throttling/errors during long GC passes; server shutdown interrupting maintenance.
Related errors
- blob configuration
- error acquiring maintenance lock
- error getting maintenance params
- error getting schedule
- error getting status
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/d5ce3420a12e2e8e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/server/server.go:1007
defer s.endUpload(ctx, src, &result)
err := errors.Wrap(s.taskmgr.Run(
ctx,
"Snapshot",
fmt.Sprintf("%v at %v", src, clock.Now().Format(time.RFC3339)),
func(ctx context.Context, ctrl uitask.Controller) error {
return inner(ctx, ctrl, &result)
}), "snapshot task")
if err != nil {
result.Error = err.Error()
}
return err
}
func (s *Server) runMaintenanceTask(ctx context.Context, dr repo.DirectRepository) error {
return errors.Wrap(s.taskmgr.Run(ctx, "Maintenance", "Periodic maintenance", func(ctx context.Context, _ uitask.Controller) error {
return repo.DirectWriteSession(ctx, dr, repo.WriteSessionOptions{
Purpose: "periodicMaintenance",
}, func(ctx context.Context, w repo.DirectRepositoryWriter) error {
return snapshotmaintenance.Run(ctx, w, maintenance.ModeAuto, false, maintenance.SafetyFull)
})
}), "unable to run maintenance")
}
// +checklocksread:s.serverMutex
func (s *Server) isLocal(src snapshot.SourceInfo) bool {
return s.rep.ClientOptions().Hostname == src.Host && !s.rep.ClientOptions().ReadOnly
}
func (s *Server) getOrCreateSourceManager(ctx context.Context, src snapshot.SourceInfo) *sourceManager {
s.serverMutex.Lock()
defer s.serverMutex.Unlock()
if s.sourceManagers[src] == nil {View on GitHub (pinned to 82495e54b5)