{"record":{"id":"9b8e9a6e5ac71b08","repo":"stamparm/maltrail","slug":"worker-config-must-load","errorCode":null,"errorMessage":"worker config must load","messagePattern":"worker config must load","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sensor/src/testkit.rs","lineNumber":326,"sourceCode":"        format!(\n            \"MONITOR_INTERFACE any\\n\\\n             CAPTURE_BUFFER 1MB\\n\\\n             PROCESS_COUNT 1\\n\\\n             UPDATE_PERIOD 999999999\\n\\\n             DISABLE_CHECK_SUDO true\\n\\\n             USE_CONDENSED_STORAGE false\\n\\\n             USE_HEURISTICS false\\n\\\n             SENSOR_NAME harness\\n\\\n             LOG_DIR {}\\n\\\n             TRAILS_FILE {}\\n\",\n            log_dir.display(),\n            trails_file.display()\n        ),\n    )\n    .expect(\"write worker config\");\n\n    let root = repo_root();\n    let mut cfg = Config::load(&config_file).expect(\"worker config must load\");\n    cfg.root = root.clone();\n    settings::init(root);\n    crate::output::init_error_log(&log_dir, false);\n\n    crate::worker::WorkerContext {\n        id,\n        cfg: Arc::new(cfg),\n        whitelist: Arc::new(Whitelist::default()),\n        store: Arc::new(TrailStore::new(build_db(&[]))),\n        output: Arc::new(OutputConfig {\n            sensor_name: \"harness\".to_string(),\n            log_dir,\n            trails_file,\n            disable_local_log_storage: false,\n            local_log_json: false,\n            console: false,\n            log_server: None,\n            log_server_secret: None,","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/stamparm/maltrail/blob/77cfb06d7606506d101bbcec0786c77166c4255e/sensor/src/testkit.rs#L308-L344","documentation":"Panic from `.expect(\"worker config must load\")` when `Config::load` rejects the just-written worker.conf. Since the harness generates the file itself, failure indicates the generated content no longer matches what the config parser accepts.","triggerScenarios":"`worker_context()` called after a refactor changed the expected config keys (e.g. MONITOR_INTERFACE, LOG_DIR, TRAILS_FILE renamed or re-validated), or Config::load gained new mandatory fields absent from the generated file.","commonSituations":"Adding a required config key in Config without updating the testkit's generated worker.conf; strict value validation added for interface names or paths; regression in the config parser itself.","solutions":["Compare the generated worker.conf keys with what Config::load currently requires and add any missing fields","Print Config::load's Err to see the specific validation failure","Update the format! template in worker_context when config keys change","Verify with a minimal standalone config that Config::load still parses the old syntax"],"exampleFix":"// before\n\"MONITOR_INTERFACE any\\nLOG_DIR ...\\nTRAILS_FILE ...\\n\"\n// after\n\"MONITOR_INTERFACE any\\nLOG_DIR ...\\nTRAILS_FILE ...\\n<NEW_REQUIRED_KEY> <value>\\n\"","handlingStrategy":"validation","validationCode":"let required = [\"MONITOR_INTERFACE\", \"LOG_DIR\", \"TRAILS_FILE\"];\nfor key in required {\n    assert!(body.contains(key), \"worker.conf missing required key {key}\");\n}","typeGuard":null,"tryCatchPattern":"let cfg = Config::load(&config_file).unwrap_or_else(|e| panic!(\"worker config must load: {e:?}\"));","preventionTips":["Update worker_context's template whenever Config gains required keys","Keep config key names centralized to avoid drift between prod and test generation","On failure, dump the generated worker.conf contents in the panic message"],"tags":["rust","config","test-harness","panic"],"backgroundTag":"missing-required-config-field","analyzedSha":"77cfb06d7606506d101bbcec0786c77166c4255e","analyzedAt":"2026-09-13T03:50:16.010Z","contentChangedAt":"2026-09-13T03:50:16.010Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}