jdx/mise · error

expected key file

Error message

expected key file

What it means

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.

Source

Thrown at src/sops.rs:314

#[cfg(test)]
mod tests {
    use super::*;

    fn read_key_file(contents: &str) -> Option<ResolvedAgeKey> {
        let tmp = tempfile::tempdir().unwrap();
        let path = tmp.path().join("keys.txt");
        file::write(&path, contents).unwrap();
        read_age_key_file(path.to_string_lossy().to_string(), &mut Ok, "test key file")
    }

    #[test]
    fn reads_multiple_age_keys_in_order() {
        let key =
            read_key_file("# first key is unrelated\r\nKEY-1\r\n\r\n# matching key\r\nKEY-2\r\n")
                .unwrap();
        let ResolvedAgeKey::File { identities, .. } = &key else {
            panic!("expected key file");
        };
        assert_eq!(identities, &["KEY-1", "KEY-2"]);
        assert_eq!(key.env_value(true), "KEY-1,KEY-2");
        assert_eq!(key.env_value(false), "KEY-1\nKEY-2");
    }

    #[test]
    fn preserves_invalid_non_comment_lines() {
        let key = read_key_file("not-an-age-key\n").unwrap();
        let ResolvedAgeKey::File { identities, .. } = key else {
            panic!("expected key file");
        };
        assert_eq!(identities, &["not-an-age-key"]);
    }

    #[test]
    fn ignores_empty_and_comment_only_key_files() {
        assert_eq!(

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. 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-...).
  2. Inspect which `ResolvedAgeKey` variant is actually returned (add a debug print or match) and adjust the expectation or the parser accordingly.
  3. If the file is intentionally empty/comment-only, handle the non-File variants explicitly instead of asserting the File variant.
  4. Verify line-ending handling (CRLF vs LF) and comment stripping in `read_key_file` haven't regressed.

Example fix

// before
let ResolvedAgeKey::File { identities, .. } = &key else {
    panic!("expected key file");
};
// after
let identities = match &key {
    ResolvedAgeKey::File { identities, .. } => identities,
    other => panic!("expected key file, got {other:?}"),
};
Defensive patterns

Strategy: type-guard

Validate before calling

// rust
if !content.lines().any(|l| !l.trim().is_empty() && !l.trim_start().starts_with('#')) {
    return Err("key file has no identity lines");
}

Type guard

fn as_key_file(key: &ResolvedAgeKey) -> Option<&Vec<String>> {
    match key {
        ResolvedAgeKey::File { identities, .. } => Some(identities),
        _ => None,
    }
}

Try / catch

// rust: replace let-else panic with a Result-returning match
let identities = match &key {
    ResolvedAgeKey::File { identities, .. } => identities,
    other => return Err(anyhow!("expected key file, got {other:?}")),
};

Prevention

When it happens

Trigger: 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`.

Common situations: 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.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/3eabb42bdec668f5. Report an issue: GitHub.