{"record":{"id":"1fa22f825117d79a","repo":"rust-lang/rust","slug":"cannot-get-jobs-of-workflow-run-workflow-run-id","errorCode":null,"errorMessage":"Cannot get jobs of workflow run {workflow_run_id}: {status}\n{}","messagePattern":"Cannot get jobs of workflow run (.+?): (.+?)\n(.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/ci/citool/src/github.rs","lineNumber":46,"sourceCode":"            let response = body\n                .read_json::<WorkflowRunJobsResponse>()\n                .context(\"cannot deserialize workflow run jobs response\")?;\n            // The CI job names have a prefix, e.g. `auto - foo`. We remove the prefix here to\n            // normalize the job name.\n            Ok(response\n                .jobs\n                .into_iter()\n                .map(|mut job| {\n                    job.name = job\n                        .name\n                        .split_once(\" - \")\n                        .map(|res| res.1.to_string())\n                        .unwrap_or_else(|| job.name);\n                    job\n                })\n                .collect())\n        } else {\n            Err(anyhow::anyhow!(\n                \"Cannot get jobs of workflow run {workflow_run_id}: {status}\\n{}\",\n                body.read_to_string()?\n            ))\n        }\n    }\n}\n\n#[derive(serde::Deserialize)]\nstruct WorkflowRunJobsResponse {\n    jobs: Vec<GitHubJob>,\n}\n\n#[derive(serde::Deserialize)]\nstruct GitHubJob {\n    name: String,\n    id: u64,\n}\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/rust-lang/rust/blob/7088e4b63a9516ebfbfe2ab2d999cf01a528ac14/src/ci/citool/src/github.rs#L28-L64","documentation":"citool's GitHubClient::get_workflow_run_jobs (src/ci/citool/src/github.rs) GETs /repos/{repo}/actions/runs/{workflow_run_id}/jobs. If GitHub returns a non-success HTTP status, it returns an anyhow error listing the workflow run id, the status, and the response body. It is a network/permission/NOT-found style failure surfaced as an anyhow::Error.","triggerScenarios":"Running citool with a workflow_run_id that does not exist, belongs to another org, or whose job list query fails auth/rate-limit (HTTP 401/403/404/5xx). The status check at github.rs:25 fails and the error is built at :46.","commonSituations":"Wrong workflow run id passed on the citool CLI; expired or scoped GITHUB_TOKEN; GitHub API rate limiting; transient GitHub 5xx; the repo slug is misspelled.","solutions":["Verify the workflow_run_id is correct and belongs to the configured repo.","Ensure GITHUB_TOKEN has actions:read on the repo and is not expired.","Retry after a brief backoff if the body indicates a rate limit (403 with X-RateLimit-Remaining: 0) or a 5xx.","Check the repo slug and that the run has not been deleted."],"exampleFix":"// before\nlet jobs = client.get_workflow_run_jobs(repo, run_id)?; // status 404 -> error\n\n// after: validate id and token before the call\nif run_id == 0 || !token_has_scope(&token, \"actions:read\") {\n    return Err(anyhow::anyhow!(\"invalid run id or token scope\"));\n}\nlet jobs = retry::retry_fn(|| client.get_workflow_run_jobs(repo, run_id), 3)?;","handlingStrategy":"retry","validationCode":"// Validate inputs before calling get_workflow_run_jobs.\nfn valid_run_id(id: u64) -> bool { id != 0 }\nfn token_has_actions_read(token: &str) -> bool { /* check scopes */ true }\n// if !valid_run_id(run_id) || !token_has_actions_read(&token) { return Err(...) }","typeGuard":null,"tryCatchPattern":"let jobs = match client.get_workflow_run_jobs(repo, run_id) {\n    Ok(j) => j,\n    Err(e) => {\n        let s = format!(\"{e:#}\");\n        if s.contains(\"403\") || s.contains(\"5\") {\n            // rate limit / server error -> backoff and retry once\n            std::thread::sleep(std::time::Duration::from_secs(5));\n            client.get_workflow_run_jobs(repo, run_id)?\n        } else { return Err(e); }\n    }\n};","preventionTips":["Pass the correct workflow_run_id and repo slug.","Ensure GITHUB_TOKEN has actions:read and is not expired.","Retry with backoff on 403-rate-limit or 5xx.","Surface the response body (already in the error) to diagnose 4xx."],"tags":["citool","github-api","network","ci","authentication"],"backgroundTag":null,"analyzedSha":"7088e4b63a9516ebfbfe2ab2d999cf01a528ac14","analyzedAt":"2026-08-10T14:17:03.603Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}