jdx/mise · error
expected ProgramArguments array, got {value:?}
Error message
expected ProgramArguments array, got {value:?} What it means
This is a test assertion panic in test_render_plist. After render_plist produces a launchd plist XML document, the test parses it with the plist crate and requires the top-level value to be a dictionary whose 'ProgramArguments' key holds an array with /bin/echo as argv[0] and hello as argv[1]. The panic fires in the catch-all match arm whenever the parsed value does not match, printing the offending value with {:?}.
Source
Thrown at src/system/launchd.rs:809
))
);
assert_eq!(
dict.get("StandardErrorPath"),
Some(&Value::String(
crate::dirs::HOME
.join("Library")
.join("Logs")
.join("sync.err.log")
.to_string_lossy()
.to_string()
))
);
match dict.get("ProgramArguments") {
Some(Value::Array(args)) => {
assert_eq!(args[0], Value::String("/bin/echo".to_string()));
assert_eq!(args[1], Value::String("hello".to_string()));
}
value => panic!("expected ProgramArguments array, got {value:?}"),
}
match dict.get("EnvironmentVariables") {
Some(Value::Dictionary(env)) => {
assert_eq!(
env.get("PATH"),
Some(&Value::String("/usr/bin:/bin".to_string()))
);
}
value => panic!("expected EnvironmentVariables dictionary, got {value:?}"),
}
assert!(plist_matches(&plist, &request));
}
#[test]
fn test_render_plist_multiple_calendar_intervals() {
let request = LaunchdRequest {
name: "sync".to_string(),
label: "dev.mise.sync".to_string(),View on GitHub (pinned to afd2eddd3a)
Solutions
- Run the test and inspect the {value:?} in the panic message to see what render_plist actually produced
- Read render_plist in src/system/launchd.rs and confirm it writes the ProgramArguments array for non-kickstart requests
- If the emitted key name changed, update either render_plist or this test so both use 'ProgramArguments'
- If the parse shape changed (e.g. values are now a different plist Value variant), update the match patterns and assertions accordingly
Example fix
// before
value => panic!("expected ProgramArguments array, got {value:?}"),
// after
// fix render_plist so it emits:
// "ProgramArguments" => Value::Array(vec![Value::String("/bin/echo".into()), Value::String("hello".into())])
// then the match arm Some(Value::Array(args)) succeeds and the panic arm is unreachable Defensive patterns
Strategy: validation
Validate before calling
// in tests: assert the shape before matching
let dict = match Value::from_reader_xml(Cursor::new(plist.as_slice())).unwrap() {
Value::Dictionary(d) => d,
v => panic!("plist root not a dictionary: {v:?}"),
};
assert!(matches!(dict.get("ProgramArguments"), Some(Value::Array(_))),
"missing/invalid ProgramArguments: {:?}", dict.get("ProgramArguments")); Type guard
fn is_string_array(v: Option<&Value>) -> bool {
matches!(v, Some(Value::Array(items)) if items.iter().all(|i| matches!(i, Value::String(_))))
} Prevention
- Keep a single serializer function for plist keys and add tests next to it
- Snapshot the rendered plist so key renames surface in review
- Assert on expected keys before deep-matching so failures point at the right key
When it happens
Trigger: render_plist(&request) returns a plist that (a) fails to parse as XML, (b) parses to a non-dictionary root, or (c) has a missing or non-array 'ProgramArguments' key — i.e. render_plist stopped emitting ProgramArguments or emitted it in a different shape.
Common situations: Refactoring render_plist to rename or drop ProgramArguments, changing the Value enum used for parsed plists, switching the plist parsing crate or format (binary vs XML), or a partial edit that emits Program keys only for kickstart-style jobs.
Related errors
- expected dictionary, got {value:?}
- expected StartCalendarInterval dictionary, got {value:?}
- expected EnvironmentVariables dictionary, got {value:?}
- expected first calendar interval dictionary, got {value:?}
- expected second calendar interval dictionary, got {value:?}
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/5215ba70194c80b2.
Report an issue: GitHub.