zed-industries/zed · error

Expected play_sound_when_agent_done to be a boolean or valid

Error message

Expected play_sound_when_agent_done to be a boolean or valid enum value

What it means

The m_2026_03_30 migration converts `agent.play_sound_when_agent_done` from a boolean to the string enum never/when_hidden/always. true→"always", false→"never", and already-valid enum strings pass through; anything else (number, object, array, or an unknown string) bails and stops settings migration.

Source

Thrown at crates/migrator/src/migrations/m_2026_03_30/settings.rs:24

pub fn make_play_sound_when_agent_done_an_enum(value: &mut Value) -> Result<()> {
    migrate_settings(value, &mut migrate_one)
}

fn migrate_one(obj: &mut serde_json::Map<String, Value>) -> Result<()> {
    let Some(play_sound) = obj
        .get_mut("agent")
        .and_then(|agent| agent.as_object_mut())
        .and_then(|agent| agent.get_mut("play_sound_when_agent_done"))
    else {
        return Ok(());
    };

    *play_sound = match play_sound {
        Value::Bool(true) => Value::String("always".to_string()),
        Value::Bool(false) => Value::String("never".to_string()),
        Value::String(s) if s == "never" || s == "when_hidden" || s == "always" => return Ok(()),
        _ => {
            anyhow::bail!("Expected play_sound_when_agent_done to be a boolean or valid enum value")
        }
    };

    Ok(())
}

View on GitHub (pinned to f4178619ac)

Solutions

  1. Set the value to one of "never", "when_hidden", or "always"
  2. Or write a boolean (true/false) and let the migration convert it
  3. Delete the key to use the default

Example fix

// before
"agent": { "play_sound_when_agent_done": "yes" }

// after
"agent": { "play_sound_when_agent_done": "always" }
Defensive patterns

Strategy: validation

Validate before calling

const VALID: [&str; 3] = ["never", "when_hidden", "always"];
fn play_sound_ok(value: &serde_json::Value) -> bool {
    value
        .pointer("/agent/play_sound_when_agent_done")
        .map_or(true, |v| {
            v.is_boolean() || v.as_str().map_or(false, |s| VALID.contains(&s))
        })
}

Type guard

fn is_valid_play_sound_setting(v: &serde_json::Value) -> bool {
    v.is_boolean()
        || v.as_str().map_or(false, |s| matches!(s, "never" | "when_hidden" | "always"))
}

Try / catch

match migrate(&mut settings) {
    Err(e) if e.to_string().contains("play_sound_when_agent_done") => {
        // set the key to "never"/"always" or remove it, re-run
    }
    r => r?,
}

Prevention

When it happens

Trigger: settings.json contains "agent": { "play_sound_when_agent_done": 1 } or an unrecognized string like "yes" when Zed runs its startup migrations.

Common situations: Guessing truthy values (1, "yes", "true") for what became a three-way enum; settings synced from older Zed versions through dotfile managers with manual edits.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/f48fc97680bd6657. Report an issue: GitHub.