ipfs/kubo · critical

embedded downgrade phase failed: %w

Error message

embedded downgrade phase failed: %w

What it means

On the downgrade path, RunHybridMigrations first runs embedded migrations backwards from the current version down to the v16 floor via RunEmbeddedMigrations (before handing off to external migrations for older versions). If that embedded downgrade fails, the error is wrapped as "embedded downgrade phase failed". Downgrades are only attempted when allowDowngrade is true.

Source

Thrown at repo/fsrepo/migrations/migrations.go:476

		if err != nil {
			return fmt.Errorf("embedded migration phase failed: %w", err)
		}

		logger.Printf("Hybrid migration completed successfully: v%d → v%d", currentVer, targetVer)
		return nil
	}

	// Case 4: Reverse hybrid migration (≥16 to <16)
	// Use embedded migrations for ≥16 steps, then external migrations for <16 steps
	logger.Printf("Starting reverse hybrid migration from version %d to %d", currentVer, targetVer)
	logger.Print("Using reverse hybrid migration strategy: embedded to v16, then external")

	// Phase 1: Use embedded migrations from current version down to v16 (if needed)
	if currentVer > embeddedMigrationsMinVersion {
		logger.Printf("Phase 1: Embedded downgrade from v%d to v%d", currentVer, embeddedMigrationsMinVersion)
		err = RunEmbeddedMigrations(ctx, embeddedMigrationsMinVersion, ipfsDir, allowDowngrade)
		if err != nil {
			return fmt.Errorf("embedded downgrade phase failed: %w", err)
		}
	}

	// Phase 2: Use external migrations from v16 to target (if needed)
	if embeddedMigrationsMinVersion > targetVer {
		logger.Printf("Phase 2: External downgrade from v%d to v%d", embeddedMigrationsMinVersion, targetVer)

		// Check for external migration binaries in PATH first
		migrations, binPaths, err := findMigrations(ctx, embeddedMigrationsMinVersion, targetVer)
		if err != nil {
			return fmt.Errorf("could not determine external migration paths: %w", err)
		}

		foundAll := true
		for _, migName := range migrations {
			if _, exists := binPaths[migName]; !exists {
				foundAll = false
				break

View on GitHub (pinned to 329838acdf)

Solutions

  1. Prefer not downgrading: re-install the newer ipfs binary matching the repo version instead of rolling the repo back
  2. If downgrade is intended, back up the repo first, then re-run with allowDowngrade=true after fixing the underlying I/O error reported by %w
  3. Check <ipfsDir>/version to see which step failed and run `ipfs fs-repo-migrations -to <ver>` manually for detailed output
  4. If the newer schema stored data the old version cannot represent, export needed data (ipfs dag/ipns/pin exports) before downgrading

Example fix

// before (downgrade attempted against repo migrated by newer kubo)
err := migrations.RunHybridMigrations(ctx, 15, ipfsPath, true)
// after (align binary with repo version instead of forcing downgrade)
ver, _ := migrations.RepoVersion(ipfsPath)
if ver > 15 {
	log.Fatalf("repo v%d requires kubo >= v%d; upgrade the binary instead of downgrading", ver, ver)
}
err = migrations.RunHybridMigrations(ctx, 15, ipfsPath, true)
Defensive patterns

Strategy: validation

Validate before calling

ver, err := migrations.RepoVersion(ipfsPath)
if err != nil {
	return err
}
if ver > 16 && !allowDowngrade {
	return fmt.Errorf("repo v%d is newer than binary target v16; refusing downgrade (set allowDowngrade deliberately)", ver)
}

Type guard

func isDowngradePhaseFailure(err error) bool {
	return err != nil && strings.Contains(err.Error(), "downgrade phase failed")
}

Try / catch

if err := migrations.RunHybridMigrations(ctx, targetVer, ipfsPath, true); err != nil {
	if strings.Contains(err.Error(), "embedded downgrade phase failed") {
		return fmt.Errorf("downgrade aborted mid-step; repo may be at an intermediate version — restore backup or re-run: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling RunHybridMigrations with targetVer < currentVer and allowDowngrade==true, when currentVer > 16 and RunEmbeddedMigrations(ctx, 16, ipfsDir, allowDowngrade) fails: a rollback migration cannot convert newer repo data, the binary running the daemon is older than the repo, or I/O/context failure mid-step.

Common situations: User downgraded the ipfs binary (e.g. rolled back a release) while the repo was already migrated by a newer version and answered yes to the downgrade prompt; rollback migrations refuse lossy conversions of data written by the newer schema; interrupted downgrade leaves the repo at an intermediate version.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/801f18e073b60a47. Report an issue: GitHub.