jdx/mise · error

expected EnvironmentVariables dictionary, got {value:?}

Error message

expected EnvironmentVariables dictionary, got {value:?}

What it means

Test assertion panic in test_render_plist. The test requires that the plist dictionary rendered by render_plist contains an 'EnvironmentVariables' key holding a dictionary in which PATH equals /usr/bin:/bin. The panic arm runs whenever the key is absent or holds a non-dictionary value, dumping the actual value with {:?}.

Source

Thrown at src/system/launchd.rs:818

                    .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(),
            program: "/bin/echo".to_string(),
            args: vec![],
            run_at_load: false,
            keep_alive: false,
            keep_alive_on_failure: false,
            start_interval: None,
            throttle_interval: None,
            nice: None,
            start_calendar_interval: Some(LaunchdCalendarIntervals::Multiple(vec![

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Inspect the {value:?} payload in the panic to see the actual parsed plist fragment
  2. Check render_plist in src/system/launchd.rs still serializes request.environment as an 'EnvironmentVariables' dictionary
  3. Restore the key or update the test to match the new intended plist schema
  4. Verify the PATH entry survives any env filtering/normalization added to render_plist

Example fix

// before
value => panic!("expected EnvironmentVariables dictionary, got {value:?}"),
// after
// ensure render_plist emits:
// "EnvironmentVariables" => Value::Dictionary(map with "PATH" => Value::String("/usr/bin:/bin"))
Defensive patterns

Strategy: validation

Validate before calling

let env = match dict.get("EnvironmentVariables") {
    Some(Value::Dictionary(e)) => e,
    other => panic!("EnvironmentVariables missing or wrong type: {other:?}"),
};
assert_eq!(env.get("PATH"), Some(&Value::String("/usr/bin:/bin".into())));

Type guard

fn as_dict(v: Option<&Value>) -> Option<&std::collections::HashMap<String, Value>> {
    match v { Some(Value::Dictionary(d)) => Some(d), _ => None }
}

Prevention

When it happens

Trigger: render_plist omits 'EnvironmentVariables' from the generated launchd plist, or emits it as a non-dictionary (array/string), so the match on dict.get("EnvironmentVariables") falls through to the catch-all arm.

Common situations: Refactoring how environment variables are serialized into the plist, accidentally skipping empty env maps, or renaming the key — all cause this test to panic during cargo test.

Related errors


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