kopia/kopia · error

no upgrade in progress

Error message

no upgrade in progress

What it means

CommitUpgrade returns this ad-hoc error when finalizing a repository format upgrade but the repository configuration carries no UpgradeLock, meaning no upgrade was ever initiated. Committing an upgrade requires an in-progress lock; without one the operation is invalid.

Solutions

  1. Call SetUpgradeLockIntent first and only then CommitUpgrade
  2. Verify the lock is present (ReadUpgradeLock) before committing
  3. Ensure all clients share the same blob storage so the lock is visible
  4. Fix orchestration so commit runs exactly once, after the drain phase

Example fix

// before
if err := fm.CommitUpgrade(ctx); err != nil { ... }
// after
lock, err := fm.ReadUpgradeLock(ctx)
if err != nil || lock == nil {
    return errors.New("upgrade lock must be set before committing upgrade")
}
if err := fm.CommitUpgrade(ctx); err != nil { ... }
Defensive patterns

Strategy: try-catch

Validate before calling

lock, err := fm.ReadUpgradeLock(ctx)
if err != nil { return err }
if lock == nil {
    return errors.New("cannot commit: no upgrade lock present")
}

Try / catch

if err := fm.CommitUpgrade(ctx); err != nil {
    if strings.Contains(err.Error(), "no upgrade in progress") {
        log.Info("nothing to commit")
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling FormatManager().CommitUpgrade(ctx) when repoConfig.UpgradeLock is nil — i.e. without a prior successful SetUpgradeLockIntent, or after the lock was already removed.

Common situations: Calling CommitUpgrade out of order in scripts or tooling; invoking it on a second connection where the lock set by another process is not visible in the cached config; retrying commit after a previous successful commit already cleared the lock.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/5efdb984111349d8. Report an issue: GitHub.

Appendix: source

Thrown at repo/format/upgrade_lock.go:107

		ctx,
		LegacyIndexPoisonBlobID,
		gather.FromSlice([]byte("The format of this repository has been upgraded and cannot be read by old clients")),
		blob.PutOptions{})
}

// CommitUpgrade removes the upgrade lock from the from the repository format
// blob. This in-effect commits the new repository format to the repository and
// resumes all access to the repository.
func (m *Manager) CommitUpgrade(ctx context.Context) error {
	if err := m.maybeRefreshNotLocked(ctx); err != nil {
		return err
	}

	m.mu.Lock()
	defer m.mu.Unlock()

	if m.repoConfig.UpgradeLock == nil {
		return errors.New("no upgrade in progress")
	}

	// poison V0 index so that old readers won't be able to open it.
	if err := WriteLegacyIndexPoisonBlob(ctx, m.blobs); err != nil {
		log(ctx).Errorf("unable to write legacy index poison blob: %v", err)
	}

	// restore the old format version
	m.repoConfig.UpgradeLock = nil

	return m.updateRepoConfigLocked(ctx)
}

// RollbackUpgrade removes the upgrade lock while also restoring the
// format-blob's original version. This method does not restore the original
// repository data format and neither does it validate against any repository
// changes. Rolling back the repository format is currently not supported and
// hence using this API could render the repository corrupted and unreadable by

View on GitHub (pinned to 82495e54b5)