Hmbown/CodeWhale · error

Could not read legacy route preferences; configuration was…

Error message

Could not read legacy route preferences; configuration was not changed

What it means

After parsing the config, migrate_legacy_route_preferences loads the legacy settings.toml to read saved route preferences. If Settings::load_legacy_route_preferences_read_only fails, it refuses with this error, leaving the configuration untouched, because proceeding would migrate from nothing.

Solutions

  1. Ensure the legacy settings.toml exists and is readable by the current user
  2. Fix file permissions on the settings file (chmod/chown as appropriate)
  3. If no legacy preferences are intended, create/initialize the settings file so the loader succeeds, or bypass the migration path

Example fix

// before
Settings::load_legacy_route_preferences_read_only()?; // file missing
// after
if settings_path.exists() {
    Settings::load_legacy_route_preferences_read_only()?;
}
Defensive patterns

Strategy: fallback

Validate before calling

if !settings_path.exists() {
    eprintln!("no legacy settings.toml; skipping preference migration");
}

Try / catch

match migrate_result {
    Err(e) if e.to_string().contains("Could not read legacy route preferences") => {
        fix_settings_file_or_skip_migration();
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling mutate_config_document (triggering the migration) while the legacy settings file is missing, unreadable, or fails to load at the OS level (permissions, I/O error).

Common situations: Running the app in a fresh environment/home directory without a legacy settings.toml; restrictive file permissions on settings.toml; disk I/O issues.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/25dca53bbfaa76dc. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/config_persistence.rs:57

    doc: &mut toml_edit::DocumentMut,
) -> anyhow::Result<()> {
    if !crate::config::is_home_config_path(path)
        || doc
            .get("route_preferences_version")
            .and_then(toml_edit::Item::as_integer)
            .is_some()
    {
        return Ok(());
    }
    let mut config: crate::config::Config = toml::from_str(&doc.to_string()).map_err(|_| {
        anyhow::anyhow!(
            "Could not parse configuration for route preference migration; contents omitted"
        )
    })?;
    let previous_config = config.clone();
    let settings =
        crate::settings::Settings::load_legacy_route_preferences_read_only().map_err(|_| {
            anyhow::anyhow!(
                "Could not read legacy route preferences; configuration was not changed"
            )
        })?;
    // An unparsable settings.toml loads as defaults carrying `load_error`, which
    // keeps the UI usable but is not evidence that no preferences were saved.
    // This migration is one-way: stamping the version over defaults would retire
    // the user's real legacy choices unread. Refuse instead, exactly as
    // `Settings::save_to_path` refuses to overwrite an unreadable document.
    // Contents stay omitted; the file may hold private text.
    anyhow::ensure!(
        settings.load_error.is_none(),
        "Could not read legacy route preferences; configuration was not changed"
    );
    config.apply_saved_selection(&settings);
    let active_identity = config.active_provider_identity(config.api_provider()).ok();
    let selector = active_identity
        .as_ref()
        .and_then(|identity| {

View on GitHub (pinned to 73e0f67d83)