spacedriveapp/spacedrive · critical · anyhow::Error

Unknown config version: {}

Error message

Unknown config version: {}

What it means

app_config.migrate() walks a chain of version steps (v1 through v6, with 6 as terminal) and any other version value falls into the catch-all arm. A version above 6 means the config file was written by a newer build than the one reading it; a garbage value means corruption or hand-editing. Because migrate() fails, config load and daemon startup fail with it.

Source

Thrown at core/src/config/app_config.rs:385

				// Migration from v3 to v4: Add multi-stream logging configuration
				self.logging = LoggingConfig::default();
				self.version = 4;
				Ok(())
			}
			4 => {
				// Migration from v4 to v5: Add proxy pairing configuration
				self.proxy_pairing = ProxyPairingConfig::default();
				self.version = 5;
				self.migrate()
			}
			5 => {
				// Migration from v5 to v6: Add Spacebot companion configuration
				self.spacebot = SpacebotConfig::default();
				self.version = 6;
				Ok(())
			}
			6 => Ok(()), // Already at target version
			v => Err(anyhow!("Unknown config version: {}", v)),
		}
	}
}

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Upgrade back to (or past) the version that wrote the config so it understands the version
  2. Or back up and remove/recreate the config file to reset to defaults (accepting loss of app settings)
  3. Never share one data dir between old and new builds; use separate --data-dir per version

Example fix

# before: data dir written by newer build
sd daemon start   # Unknown config version: 7

# after: quarantine old config, start fresh
mv ~/.spacedrive/app_config.json ~/.spacedrive/app_config.json.bak
sd daemon start
Defensive patterns

Strategy: validation

Validate before calling

fn config_version_supported(path: &std::path::Path) -> anyhow::Result<bool> {
    let v: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(path)?)?;
    Ok(v.get("version").and_then(|v| v.as_u64()).map_or(false, |n| (1..=6).contains(&n)))
}

Type guard

fn is_known_config_version(v: u64) -> bool {
    (1..=6).contains(&v)
}

Try / catch

match config.migrate() {
    Ok(()) => {}
    Err(e) if e.to_string().contains("Unknown config version") => {
        eprintln!("Config was written by a newer build. Upgrade the daemon, or back up and remove the config to reset.");
        std::process::exit(1);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Downgrading the daemon/CLI after a newer release wrote a v7+ config; two builds of different versions sharing one data dir; manual edits to the version field.

Common situations: Rolling back a release to fix a regression; testing builds side by side against the same data dir; config files synced between machines running different versions.

Related errors


AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16). Data as JSON: /api/errors/9acfd836827b38a8. Report an issue: GitHub.