{"record":{"id":"0bb212fa69e755b6","repo":"rust-lang/rust-analyzer","slug":"cargo-runnable-should-deserialize","errorCode":null,"errorMessage":"cargo runnable should deserialize","messagePattern":"cargo runnable should deserialize","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/rust-analyzer/src/lsp/ext.rs","lineNumber":1009,"sourceCode":"        };\n        let expected = json!({\n            \"label\": \"cargo test -p my-crate\",\n            \"kind\": \"cargo\",\n            \"args\": {\n                \"environment\": {\"RUSTC_TOOLCHAIN\": \"/toolchain\"},\n                \"cwd\": \"/project\",\n                \"overrideCargo\": null,\n                \"workspaceRoot\": \"/project\",\n                \"cargoArgs\": [\"test\", \"--package\", \"my-crate\", \"--lib\"],\n                \"executableArgs\": [\"my_test\", \"--exact\"],\n            }\n        });\n\n        let serialized = serde_json::to_value(&runnable).expect(\"serialized runnable\");\n        assert_eq!(serialized, expected);\n\n        let deserialized: Runnable =\n            serde_json::from_value(expected).expect(\"cargo runnable should deserialize\");\n        let RunnableArgs::Cargo(cargo) = &deserialized.args else {\n            panic!(\"expected Cargo variant, got {:?}\", deserialized.args);\n        };\n        assert_eq!(cargo.cargo_args, vec![\"test\", \"--package\", \"my-crate\", \"--lib\"]);\n        assert_eq!(cargo.executable_args, vec![\"my_test\", \"--exact\"]);\n    }\n\n    #[test]\n    fn shell_runnable_round_trips() {\n        let runnable = Runnable {\n            label: \"nextest test_one\".to_owned(),\n            location: None,\n            args: RunnableArgs::Shell(ShellRunnableArgs {\n                environment: [(\"RUSTC_TOOLCHAIN\".to_owned(), \"/toolchain\".to_owned())]\n                    .into_iter()\n                    .collect(),\n                cwd: \"/project\".into(),\n                program: \"cargo\".into(),","sourceCodeStart":991,"sourceCodeEnd":1027,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/rust-analyzer/src/lsp/ext.rs#L991-L1027","documentation":"The companion assertion of the cargo-runnable round-trip test: it deserializes the expected JSON back into Runnable and expects success. A panic here means the JSON fixture no longer matches the Runnable/RunnableArgs serde schema — serde_json::from_value returned a deserialization error (missing field, wrong shape, or the kind tag not selecting the Cargo variant).","triggerScenarios":"Changing the serde representation of RunnableArgs::Cargo (field names, tagging strategy like untagged vs internally tagged, removing/renaming cargoArgs or executableArgs) so the fixture JSON in the test fails to deserialize.","commonSituations":"Contributors refactoring the rust-analyzer runnable LSP extension types, accidentally switching to a tag-less enum where a shell payload parses as cargo, or renaming fields without updating the test's expected JSON.","solutions":["Compare the fixture JSON against the current serde derive on Runnable and fix mismatched field names/shape.","Ensure the enum uses a discriminant (the `kind` tag) so Cargo and Shell variants deserialize distinctly.","Run with RUST_BACKTRACE=1 and print the serde error to see the exact missing/mismatched field.","Update the expected JSON (via UPDATE_EXPECT=1 or manually) only after verifying the new schema is intended and the client extension matches."],"exampleFix":"// before: untagged enum\n#[derive(Serialize, Deserialize)]\nenum RunnableArgs { Cargo(CargoRunnable), Shell(ShellRunnable) }\n// after: internally tagged so variants are distinguishable\n#[derive(Serialize, Deserialize)]\n#[serde(tag = \"kind\", rename_all = \"snake_case\")]\nenum RunnableArgs { Cargo(CargoRunnable), Shell(ShellRunnable) }","handlingStrategy":"type-guard","validationCode":"// validate fixture matches current schema before from_value\nlet value = serde_json::to_value(&runnable).expect(\"fixture must serialize\");\nassert!(value.get(\"kind\").is_some(), \"runnable payload must carry a kind tag\");","typeGuard":"fn is_cargo_runnable(v: &serde_json::Value) -> bool {\n    v.get(\"kind\").and_then(|k| k.as_str()) == Some(\"cargo\")\n        && v.get(\"cargoArgs\").map(|a| a.is_array()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Keep an explicit `kind` tag on tagged enums so variants are distinguishable.","Update fixture JSON and struct fields together in the same commit.","Inspect serde errors with match instead of expect to see field mismatches.","Mirror schema changes in the VS Code client extension."],"tags":["tests","serde","deserialization","lsp-ext"],"backgroundTag":"serde-deserialization-schema-mismatch","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}