rust-lang/rust · error · anyhow::Error

Cannot get jobs of workflow run {workflow_run_id}: {status}

Error message

Cannot get jobs of workflow run {workflow_run_id}: {status}
{}

What it means

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.

Source

Thrown at src/ci/citool/src/github.rs:46

            let response = body
                .read_json::<WorkflowRunJobsResponse>()
                .context("cannot deserialize workflow run jobs response")?;
            // The CI job names have a prefix, e.g. `auto - foo`. We remove the prefix here to
            // normalize the job name.
            Ok(response
                .jobs
                .into_iter()
                .map(|mut job| {
                    job.name = job
                        .name
                        .split_once(" - ")
                        .map(|res| res.1.to_string())
                        .unwrap_or_else(|| job.name);
                    job
                })
                .collect())
        } else {
            Err(anyhow::anyhow!(
                "Cannot get jobs of workflow run {workflow_run_id}: {status}\n{}",
                body.read_to_string()?
            ))
        }
    }
}

#[derive(serde::Deserialize)]
struct WorkflowRunJobsResponse {
    jobs: Vec<GitHubJob>,
}

#[derive(serde::Deserialize)]
struct GitHubJob {
    name: String,
    id: u64,
}

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Verify the workflow_run_id is correct and belongs to the configured repo.
  2. Ensure GITHUB_TOKEN has actions:read on the repo and is not expired.
  3. Retry after a brief backoff if the body indicates a rate limit (403 with X-RateLimit-Remaining: 0) or a 5xx.
  4. Check the repo slug and that the run has not been deleted.

Example fix

// before
let jobs = client.get_workflow_run_jobs(repo, run_id)?; // status 404 -> error

// after: validate id and token before the call
if run_id == 0 || !token_has_scope(&token, "actions:read") {
    return Err(anyhow::anyhow!("invalid run id or token scope"));
}
let jobs = retry::retry_fn(|| client.get_workflow_run_jobs(repo, run_id), 3)?;
Defensive patterns

Strategy: retry

Validate before calling

// Validate inputs before calling get_workflow_run_jobs.
fn valid_run_id(id: u64) -> bool { id != 0 }
fn token_has_actions_read(token: &str) -> bool { /* check scopes */ true }
// if !valid_run_id(run_id) || !token_has_actions_read(&token) { return Err(...) }

Try / catch

let jobs = match client.get_workflow_run_jobs(repo, run_id) {
    Ok(j) => j,
    Err(e) => {
        let s = format!("{e:#}");
        if s.contains("403") || s.contains("5") {
            // rate limit / server error -> backoff and retry once
            std::thread::sleep(std::time::Duration::from_secs(5));
            client.get_workflow_run_jobs(repo, run_id)?
        } else { return Err(e); }
    }
};

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/1fa22f825117d79a. Report an issue: GitHub.