stamparm/maltrail · error

config must load

Error message

config must load

What it means

Same test-helper expect: `Config::load(&path).expect("config must load")` asserts that a base config plus PROCESS_COUNT 16 loads cleanly. The test documents that PROCESS_COUNT must not influence capture_workers; the expect fails only when Config::load rejects the file outright.

Solutions

  1. Inspect the Err from Config::load for the exact failing key
  2. Adjust the new validation to accept the minimal base config
  3. Update the fixture if a genuinely required field is missing

Example fix

// before
let base = "MONITOR_INTERFACE any\nCAPTURE_BUFFER 1MB\nLOG_DIR /tmp\n";
// after
let base = "MONITOR_INTERFACE any\nCAPTURE_BUFFER 1MB\nLOG_DIR /tmp\nUPDATE_PERIOD 86400\n";
Defensive patterns

Strategy: try-catch

Validate before calling

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

Try / catch

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

Prevention

When it happens

Trigger: Config::load returns Err for the base config (MONITOR_INTERFACE any / CAPTURE_BUFFER 1MB / LOG_DIR /tmp / UPDATE_PERIOD 86400) plus 'PROCESS_COUNT 16', e.g. after a new required-field or range check was introduced.

Common situations: Adding validation (e.g. rejecting unknown keys or making a new field mandatory) that breaks previously-loading minimal configs.

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/dc11f77f808c34a5. Report an issue: GitHub.

Appendix: source

Thrown at sensor/src/config.rs:1343

        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);
            std::fs::write(&path, format!("{base}{extra}")).unwrap();
            Config::load(&path).expect("config must load")
        };

        // PROCESS_COUNT alone must NOT fan out: it is sensor.py's worker-process count, and
        // honouring it here degraded the scan heuristics of anyone who never touched the setting.
        assert_eq!(write("pc.conf", "PROCESS_COUNT 16\n").capture_workers, 1);
        // Both explicit knobs still work, and still win.
        assert_eq!(write("cw.conf", "CAPTURE_WORKERS 4\n").capture_workers, 4);
        assert_eq!(write("cf.conf", "CAPTURE_FANOUT 8\n").capture_workers, 8);
        assert!(write("auto.conf", "CAPTURE_WORKERS auto\n").capture_workers >= 1);
    }

    #[test]
    fn fanout_defaults_to_source_affinity_only_when_it_matters() {
        let dir = std::env::temp_dir().join("mt-cfg-fanout-default");
        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)