canopy-network/canopy · error

finalize backup: %w

Error message

finalize backup: %w

What it means

Wrapped failure (fmt.Errorf with %w) for the final phase of the backup rotation: renaming the freshly completed tempBackupDir into place as the active backupDir. The checkpoint, height file, and prior-backup rotation all succeeded, but the final swap failed, leaving the backup incomplete.

Source

Thrown at store/store.go:800

		// perform the backup using pebble's checkpointing mechanism which creates a
		// consistent snapshot of the database at the specified directory
		if err = s.db.Checkpoint(tempBackupDir); err != nil {
			err = fmt.Errorf("checkpoint creation: %w", err)
			return
		}
		// write the current height to a separate file
		heightFile := filepath.Join(tempBackupDir, "height.txt")
		if err = os.WriteFile(heightFile, fmt.Appendf(nil, "%d", version), 0644); err != nil {
			err = fmt.Errorf("write height file: %w", err)
			return
		}
		if err = os.Rename(backupDir, prevBackupDir); err != nil && !os.IsNotExist(err) {
			err = fmt.Errorf("rotate backup: %w", err)
			return
		}
		// promote: atomically move the temp backup into the active slot
		if err = os.Rename(tempBackupDir, backupDir); err != nil {
			err = fmt.Errorf("finalize backup: %w", err)
			return
		}
		backupDuration := time.Since(start)
		// log results
		s.log.Infof("backup completed at height [%d] in %s", version, backupDuration)
		// update metrics
		s.metrics.UpdateStoreJobMetrics(0, 0, backupDuration)
	}()
}

// Compact runs Pebble range compaction over the prefix range
func (s *Store) Compact(version uint64, prefix []byte) lib.ErrorI {
	// compactions are not allowed to run concurrently to not intertwine with the keys
	if !s.compaction.CompareAndSwap(false, true) {
		s.log.Debugf("key compaction skipped [%d] [%s]: already in progress", version, prefix)
		return nil
	}
	defer s.compaction.Store(false)

View on GitHub (pinned to ee8197d91d)

Solutions

  1. Check the wrapped OS error for rename failures (permissions, target path busy/locked, cross-device).
  2. Clean up leftover tempBackupDir before the next backup cycle to avoid conflicts.
  3. Retry the backup; the prior backupDir should still be intact since the swap is the last step.
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at store/store.go:800 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06). Data as JSON: /api/errors/ededea56cd9ea635. Report an issue: GitHub.