{"record":{"id":"f48fc97680bd6657","repo":"zed-industries/zed","slug":"expected-play-sound-when-agent-done-to-be-a-boolea","errorCode":null,"errorMessage":"Expected play_sound_when_agent_done to be a boolean or valid enum value","messagePattern":"Expected play_sound_when_agent_done to be a boolean or valid enum value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/migrator/src/migrations/m_2026_03_30/settings.rs","lineNumber":24,"sourceCode":"pub fn make_play_sound_when_agent_done_an_enum(value: &mut Value) -> Result<()> {\n    migrate_settings(value, &mut migrate_one)\n}\n\nfn migrate_one(obj: &mut serde_json::Map<String, Value>) -> Result<()> {\n    let Some(play_sound) = obj\n        .get_mut(\"agent\")\n        .and_then(|agent| agent.as_object_mut())\n        .and_then(|agent| agent.get_mut(\"play_sound_when_agent_done\"))\n    else {\n        return Ok(());\n    };\n\n    *play_sound = match play_sound {\n        Value::Bool(true) => Value::String(\"always\".to_string()),\n        Value::Bool(false) => Value::String(\"never\".to_string()),\n        Value::String(s) if s == \"never\" || s == \"when_hidden\" || s == \"always\" => return Ok(()),\n        _ => {\n            anyhow::bail!(\"Expected play_sound_when_agent_done to be a boolean or valid enum value\")\n        }\n    };\n\n    Ok(())\n}\n","sourceCodeStart":6,"sourceCodeEnd":30,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/migrator/src/migrations/m_2026_03_30/settings.rs#L6-L30","documentation":"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.","triggerScenarios":"settings.json contains \"agent\": { \"play_sound_when_agent_done\": 1 } or an unrecognized string like \"yes\" when Zed runs its startup migrations.","commonSituations":"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.","solutions":["Set the value to one of \"never\", \"when_hidden\", or \"always\"","Or write a boolean (true/false) and let the migration convert it","Delete the key to use the default"],"exampleFix":"// before\n\"agent\": { \"play_sound_when_agent_done\": \"yes\" }\n\n// after\n\"agent\": { \"play_sound_when_agent_done\": \"always\" }","handlingStrategy":"validation","validationCode":"const VALID: [&str; 3] = [\"never\", \"when_hidden\", \"always\"];\nfn play_sound_ok(value: &serde_json::Value) -> bool {\n    value\n        .pointer(\"/agent/play_sound_when_agent_done\")\n        .map_or(true, |v| {\n            v.is_boolean() || v.as_str().map_or(false, |s| VALID.contains(&s))\n        })\n}","typeGuard":"fn is_valid_play_sound_setting(v: &serde_json::Value) -> bool {\n    v.is_boolean()\n        || v.as_str().map_or(false, |s| matches!(s, \"never\" | \"when_hidden\" | \"always\"))\n}","tryCatchPattern":"match migrate(&mut settings) {\n    Err(e) if e.to_string().contains(\"play_sound_when_agent_done\") => {\n        // set the key to \"never\"/\"always\" or remove it, re-run\n    }\n    r => r?,\n}","preventionTips":["Write booleans or the exact enum strings only","Avoid truthy shorthand like 1 or \"yes\" in settings.json","Review agent settings after upgrades; enums replace booleans over time"],"tags":["zed","settings","migration","agent","sound","enum"],"backgroundTag":"settings-schema-validation-failed","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}