{"record":{"id":"3eabb42bdec668f5","repo":"jdx/mise","slug":"expected-key-file","errorCode":null,"errorMessage":"expected key file","messagePattern":"expected key file","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/sops.rs","lineNumber":314,"sourceCode":"\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn read_key_file(contents: &str) -> Option<ResolvedAgeKey> {\n        let tmp = tempfile::tempdir().unwrap();\n        let path = tmp.path().join(\"keys.txt\");\n        file::write(&path, contents).unwrap();\n        read_age_key_file(path.to_string_lossy().to_string(), &mut Ok, \"test key file\")\n    }\n\n    #[test]\n    fn reads_multiple_age_keys_in_order() {\n        let key =\n            read_key_file(\"# first key is unrelated\\r\\nKEY-1\\r\\n\\r\\n# matching key\\r\\nKEY-2\\r\\n\")\n                .unwrap();\n        let ResolvedAgeKey::File { identities, .. } = &key else {\n            panic!(\"expected key file\");\n        };\n        assert_eq!(identities, &[\"KEY-1\", \"KEY-2\"]);\n        assert_eq!(key.env_value(true), \"KEY-1,KEY-2\");\n        assert_eq!(key.env_value(false), \"KEY-1\\nKEY-2\");\n    }\n\n    #[test]\n    fn preserves_invalid_non_comment_lines() {\n        let key = read_key_file(\"not-an-age-key\\n\").unwrap();\n        let ResolvedAgeKey::File { identities, .. } = key else {\n            panic!(\"expected key file\");\n        };\n        assert_eq!(identities, &[\"not-an-age-key\"]);\n    }\n\n    #[test]\n    fn ignores_empty_and_comment_only_key_files() {\n        assert_eq!(","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/sops.rs#L296-L332","documentation":"This is a test-only panic emitted by a Rust `let-else` destructuring assertion in src/sops.rs. `read_key_file` returns a `ResolvedAgeKey` enum, and the test asserts the variant is `ResolvedAgeKey::File` (a parsed key file containing identities); any other variant (e.g. an env-based or empty resolution) falls into the else branch and panics with 'expected key file'. It signals that the age key parser did not produce a file-backed key from the given contents.","triggerScenarios":"Calling `read_key_file` with contents that resolve to a non-`File` variant of `ResolvedAgeKey` — e.g. content that the parser treats as empty, comment-only, or otherwise not yielding identity lines — inside a context (test or code copy) that expects `ResolvedAgeKey::File`.","commonSituations":"Feeding a key file that contains only comments or blank lines; a parser change that reclassifies valid KEY lines; refactoring `read_key_file` so multi-line or CRLF files resolve to a different variant; pointing at an age key file that is actually a placeholder.","solutions":["Ensure the key file content passed to `read_key_file` contains at least one non-comment identity line (e.g. a line starting with AGE-... or KEY-...).","Inspect which `ResolvedAgeKey` variant is actually returned (add a debug print or match) and adjust the expectation or the parser accordingly.","If the file is intentionally empty/comment-only, handle the non-File variants explicitly instead of asserting the File variant.","Verify line-ending handling (CRLF vs LF) and comment stripping in `read_key_file` haven't regressed."],"exampleFix":"// before\nlet ResolvedAgeKey::File { identities, .. } = &key else {\n    panic!(\"expected key file\");\n};\n// after\nlet identities = match &key {\n    ResolvedAgeKey::File { identities, .. } => identities,\n    other => panic!(\"expected key file, got {other:?}\"),\n};","handlingStrategy":"type-guard","validationCode":"// rust\nif !content.lines().any(|l| !l.trim().is_empty() && !l.trim_start().starts_with('#')) {\n    return Err(\"key file has no identity lines\");\n}","typeGuard":"fn as_key_file(key: &ResolvedAgeKey) -> Option<&Vec<String>> {\n    match key {\n        ResolvedAgeKey::File { identities, .. } => Some(identities),\n        _ => None,\n    }\n}","tryCatchPattern":"// rust: replace let-else panic with a Result-returning match\nlet identities = match &key {\n    ResolvedAgeKey::File { identities, .. } => identities,\n    other => return Err(anyhow!(\"expected key file, got {other:?}\")),\n};","preventionTips":["Always include the unexpected value in panic messages for debuggability.","Validate key file contents (non-comment lines present) before parsing.","Add unit tests for empty and comment-only key files.","Prefer returning Err over panicking in library code paths."],"tags":["rust","test-assertion","age-keys","enum-variant"],"backgroundTag":"invalid-enum-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}