stamparm/maltrail · error

must load

Error message

must load

What it means

Not a runtime error but a test-side expect: the test helper `write()` builds a temp config file and calls Config::load, expecting success ('must load'). The expect fires only if Config::load rejects a config the test believes is valid, e.g. after an overly strict validation change. The declared 'cfg' here is the test closure's return value, not the production open_live path.

Solutions

  1. Run the failing test and read the underlying Config::load error message to see which key is rejected
  2. Fix Config::load so valid multi-endpoint SYSLOG_SERVER/LOGSTASH_SERVER lines still parse, or correct the test fixture if it is genuinely invalid

Example fix

// before
assert!(write("bad2.conf", "SYSLOG_SERVER 1.2.3.4:514, nonsense\n").is_ok());
// after
assert!(write("bad2.conf", "SYSLOG_SERVER 1.2.3.4:514, nonsense\n").is_err());
Defensive patterns

Strategy: try-catch

Validate before calling

let cfg = Config::load(&path);
assert!(cfg.is_ok(), "config rejected: {:?}", cfg.err());

Try / catch

match Config::load(&path) {
    Ok(cfg) => proceed(cfg),
    Err(e) => eprintln!("config {} failed to load: {e}", path.display()),
}

Prevention

When it happens

Trigger: Config::load returns Err for a config the test wrote (multi/mixed/one.conf with valid SYSLOG_SERVER/LOGSTASH_SERVER lines), typically after a new validation rule was added to Config::load.

Common situations: A developer adds endpoint or field validation to Config::load that unintentionally rejects previously-valid configs, breaking the unit tests that assert these files load.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13). Data as JSON: /api/errors/2820400b973e79b8. Report an issue: GitHub.

Appendix: source

Thrown at sensor/src/config.rs:1323

    #[test]
    fn several_remote_logging_endpoints_are_accepted_and_all_validated() {
        let dir = std::env::temp_dir().join("mt-cfg-endpoints");
        let _ = std::fs::create_dir_all(&dir);
        let base = "MONITOR_INTERFACE any\nCAPTURE_BUFFER 1MB\nLOG_DIR /tmp\nUPDATE_PERIOD 86400\n";
        let write = |name: &str, extra: &str| {
            let path = dir.join(name);
            std::fs::write(&path, format!("{base}{extra}")).unwrap();
            Config::load(&path)
        };

        // one option, several collectors: comma, semicolon and whitespace all separate
        let cfg = write("multi.conf", "SYSLOG_SERVER 1.2.3.4:514, 5.6.7.8:514\n").expect("must load");
        assert_eq!(split_endpoints(&cfg.syslog_server), vec!["1.2.3.4:514", "5.6.7.8:514"]);
        let cfg = write("mixed.conf", "LOGSTASH_SERVER 1.2.3.4:5000;5.6.7.8:5000 9.9.9.9:5000\n").expect("must load");
        assert_eq!(split_endpoints(&cfg.logstash_server), vec!["1.2.3.4:5000", "5.6.7.8:5000", "9.9.9.9:5000"]);

        // a single endpoint keeps behaving exactly as before
        let cfg = write("one.conf", "SYSLOG_SERVER 1.2.3.4:514\n").expect("must load");
        assert_eq!(split_endpoints(&cfg.syslog_server), vec!["1.2.3.4:514"]);
        assert!(split_endpoints("").is_empty());

        // EVERY endpoint is validated: a typo in the second is as fatal as one in the first,
        // because forwarding to one of two configured collectors is silent half-failure.
        assert!(write("bad2.conf", "SYSLOG_SERVER 1.2.3.4:514, nonsense\n").is_err());
        assert!(write("bad1.conf", "SYSLOG_SERVER nonsense, 1.2.3.4:514\n").is_err());
        assert!(write("badls.conf", "LOGSTASH_SERVER 1.2.3.4:5000, 5.6.7.8\n").is_err());
    }

    #[test]
    fn worker_count_is_opt_in() {
        let dir = std::env::temp_dir().join("mt-cfg-workers");
        let _ = std::fs::create_dir_all(&dir);
        let base = "MONITOR_INTERFACE any\nCAPTURE_BUFFER 1MB\nLOG_DIR /tmp\nUPDATE_PERIOD 86400\n";

        let write = |name: &str, extra: &str| {
            let path = dir.join(name);

View on GitHub (pinned to 77cfb06d76)