{"record":{"id":"040f5af1e43b8a9a","repo":"wasmerio/wasmer","slug":"invocation-start-must-not-be-after-end","errorCode":null,"errorMessage":"invocation start must not be after end","messagePattern":"invocation start must not be after end","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"lib/backend-api/src/query.rs","lineNumber":602,"sourceCode":"\n    Ok(logs_from_connection(invocation.logs))\n}\n\nfn default_cron_invocation_window(\n    start: Option<OffsetDateTime>,\n    end: Option<OffsetDateTime>,\n) -> Result<(OffsetDateTime, OffsetDateTime), anyhow::Error> {\n    let (start, end) = match (start, end) {\n        (Some(start), Some(end)) => (start, end),\n        (Some(start), None) => (start, OffsetDateTime::now_utc()),\n        (None, Some(end)) => (end - time::Duration::days(31), end),\n        (None, None) => {\n            let end = OffsetDateTime::now_utc();\n            (end - time::Duration::days(31), end)\n        }\n    };\n    if start > end {\n        bail!(\"invocation start must not be after end\");\n    }\n    Ok((start, end))\n}\n\nfn logs_from_connection(connection: types::CronJobLogConnection) -> Vec<types::CronJobLog> {\n    connection\n        .edges\n        .into_iter()\n        .flatten()\n        .filter_map(|edge| edge.node)\n        .collect()\n}\n\n/// Load the S3 credentials.\n///\n/// S3 can be used to get access to an apps volumes.\npub async fn get_app_s3_credentials(\n    client: &WasmerClient,","sourceCodeStart":584,"sourceCodeEnd":620,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/backend-api/src/query.rs#L584-L620","documentation":"default_cron_invocation_window computes the (start, end) time window used when querying cron job invocations, defaulting end=now / start=now-31 days when both bounds are omitted. If the caller supplies a start after end, it bails with 'invocation start must not be after end' as input validation.","triggerScenarios":"Calling get_cron_job_invocations_page or get_cron_job_invocations_page_by_id with an explicit window where start > end — e.g. swapped arguments, negative duration math, or passing future end times.","commonSituations":"Passing (end, start) in the wrong order; computing timestamps with timezone/DST mix-ups; using a clock-skewed host so now_utc() lands before the caller's start.","solutions":["Swap/order the timestamps so start <= end before calling the API.","Normalize both timestamps to UTC (OffsetDateTime::now_utc() comparisons) and strip incompatible offsets.","Add a clamp helper: if start > end, either error early in your code or clamp to a 31-day default window."],"exampleFix":"// before\nlet window = (end_ts, start_ts); // reversed\nlet page = get_cron_job_invocations_page(&client, name, window).await?;\n// after\nlet (start, end) = if start_ts > end_ts { (end_ts, start_ts) } else { (start_ts, end_ts) };\nlet page = get_cron_job_invocations_page(&client, name, (start, end)).await?;","handlingStrategy":"validation","validationCode":"fn valid_window(start: OffsetDateTime, end: OffsetDateTime) -> bool { start <= end }\n// or clamp: let (start, end) = if start > end { (end, start) } else { (start, end) };","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always order timestamps (start, end) — never rely on argument position memory","Normalize all timestamps to UTC before passing them","Use the default window (omit bounds) unless a custom range is truly needed"],"tags":["backend-api","validation","datetime","cron"],"backgroundTag":"invalid-time-range","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}