{"record":{"id":"19578188ee655aae","repo":"affaan-m/ECC","slug":"legacy-scheduler-jobs-file-must-be-a-json-object-o","errorCode":null,"errorMessage":"legacy scheduler jobs file must be a JSON object or array: {}","messagePattern":"legacy scheduler jobs file must be a JSON object or array: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/main.rs","lineNumber":5531,"sourceCode":"    let source_path = jobs_path\n        .strip_prefix(source)\n        .unwrap_or(&jobs_path)\n        .display()\n        .to_string();\n\n    let entries: Vec<&serde_json::Value> = match &value {\n        serde_json::Value::Array(items) => items.iter().collect(),\n        serde_json::Value::Object(map) => {\n            if let Some(items) = [\"jobs\", \"schedules\", \"tasks\"]\n                .iter()\n                .find_map(|key| map.get(*key).and_then(serde_json::Value::as_array))\n            {\n                items.iter().collect()\n            } else {\n                vec![&value]\n            }\n        }\n        _ => anyhow::bail!(\n            \"legacy scheduler jobs file must be a JSON object or array: {}\",\n            jobs_path.display()\n        ),\n    };\n\n    Ok(entries\n        .into_iter()\n        .enumerate()\n        .map(|(index, value)| build_legacy_schedule_draft(value, index, &source_path))\n        .collect())\n}\n\nfn load_legacy_remote_dispatch_drafts(source: &Path) -> Result<Vec<LegacyRemoteDispatchDraft>> {\n    let gateway_dir = source.join(\"gateway\");\n    if !gateway_dir.is_dir() {\n        return Ok(Vec::new());\n    }\n","sourceCodeStart":5513,"sourceCodeEnd":5549,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/main.rs#L5513-L5549","documentation":"Thrown by load_legacy_schedule_drafts when the parsed cron/jobs.json is a JSON value that is neither an object nor an array at the top level (i.e. a string, number, boolean, or null). The importer accepts an array of jobs, an object, or an object with a jobs/schedules/tasks array key; any other top-level scalar is rejected because it cannot yield schedule entries.","triggerScenarios":"The legacy cron/jobs.json file contains a bare scalar such as '5', 'true', 'null', or a quoted string instead of a JSON object or array. Also triggered if the file was overwritten by a log line or a misconfigured tool that wrote a non-structured value.","commonSituations":"A hand-edited jobs.json saved as a string by mistake; a JSON Lines file renamed to jobs.json; a config generator that wrote a single scalar value; an empty/null top-level value.","solutions":["Open cron/jobs.json and confirm it is a JSON object or array (e.g. '{\"jobs\":[...]}' or '[...]').","If the schedules live in JSONL, rename/move the file so it is not picked up as jobs.json, or wrap the entries in an array.","Validate the file with 'jq . cron/jobs.json' before running the importer; jq will surface structural problems.","Convert a scalar/null file to '{\"jobs\":[]}' if no schedules exist yet."],"exampleFix":"// before (cron/jobs.json)\n\"nightly-reindex\"\n\n// after (cron/jobs.json)\n{\n  \"jobs\": [\n    { \"name\": \"nightly-reindex\", \"cron\": \"0 2 * * *\", \"task\": \"reindex\" }\n  ]\n}","handlingStrategy":"validation","validationCode":"fn validate_jobs_json(text: &str) -> anyhow::Result<()> {\n    let v: serde_json::Value = serde_json::from_str(text)?;\n    if !v.is_array() && !v.is_object() {\n        anyhow::bail!(\"jobs file must be a JSON object or array\");\n    }\n    Ok(())\n}","typeGuard":"fn is_jobs_container(v: &serde_json::Value) -> bool {\n    v.is_array()\n        || v.as_object().map_or(false, |m| {\n            [\"jobs\", \"schedules\", \"tasks\"].iter().any(|k| m.get(*k).map_or(false, |x| x.is_array()))\n        })\n}","tryCatchPattern":null,"preventionTips":["Run 'jq . cron/jobs.json' before importing to catch structural problems.","Keep jobs.json as an object with a 'jobs' array for clarity."],"tags":["legacy-migration","scheduler","json","input-validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}