{"record":{"id":"6cfc2f1604f1c89e","repo":"xai-org/grok-build","slug":"git-fetch-origin-oid-skipped-restore-fetch-budg","errorCode":null,"errorMessage":"git fetch origin {oid} skipped: restore fetch budget exhausted","messagePattern":"git fetch origin (.+?) skipped: restore fetch budget exhausted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-workspace/src/restore_fetch.rs","lineNumber":242,"sourceCode":"        (SkippedInvalidOid, SkippedInvalidOid) => EnsureCommitsOutcome::SkippedInvalidOid,\n    }\n}\n\npub(crate) fn fetch_if_missing<G: RestoreGit>(\n    repo: &Path,\n    oid: &str,\n    git: &G,\n    timeout: Duration,\n) -> Result<FetchCommitOutcome> {\n    if !is_full_object_id(oid) {\n        tracing::warn!(oid = %oid, \"restore_fetch: skipping non-oid refspec\");\n        return Ok(FetchCommitOutcome::SkippedInvalidOid);\n    }\n    if git.has_object(repo, oid) {\n        return Ok(FetchCommitOutcome::AlreadyPresent);\n    }\n    if timeout.is_zero() {\n        bail!(\"git fetch origin {oid} skipped: restore fetch budget exhausted\");\n    }\n    git.fetch_oid(repo, oid, timeout)?;\n    Ok(FetchCommitOutcome::Fetched)\n}\n\n/// Whether `git cat-file -t` resolves `spec` in `repo`.\npub fn git_object_exists(repo: &Path, spec: &str) -> bool {\n    let output = git_command()\n        .current_dir(repo)\n        .args([\"cat-file\", \"-t\", spec])\n        .stdout(Stdio::null())\n        .stderr(Stdio::null())\n        .output();\n    matches!(output, Ok(o) if o.status.success())\n}\n\n/// Fetch a checkout target (full oid or simple ref) if it is not already local.\n///","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/restore_fetch.rs#L224-L260","documentation":"fetch_if_missing performs a targeted `git fetch origin <oid>` during workspace restore, but only if a fetch budget (Duration) remains. When the passed timeout is exactly zero — the shared restore deadline has already been spent by earlier fetches or work — the library refuses to start a fetch it cannot bound and throws this error naming the oid it would have fetched.","triggerScenarios":"Calling fetch_if_missing (directly or via fetch_commit_if_missing / ensure_commits_reachable) after the shared restore-fetch budget is exhausted: earlier head/base fetches consumed the deadline, budget accounting reached zero, or a caller passes Duration::ZERO while the object is genuinely missing from the local repo.","commonSituations":"Restoring a snapshot repo where the head commit and the public base commit both need fetching on a slow network, exhausting the budget before the second fetch; restoring many commits sequentially against a large monorepo over a slow VPN; a hung first fetch whose teardown reserve consumed the remaining budget.","solutions":["Increase the restore fetch budget/deadline so time remains when this oid is fetched, or restore again — the budget is per-run and resets on retry","Pre-populate the repo (git fetch origin <oid> manually or a fuller clone) so has_object returns true and no budget is consumed","Reduce objects needing fetch: restore from a snapshot whose commits are already local, or check connectivity to origin to speed earlier fetches","Treat as non-fatal per the API contract: the error does not mean the object is unreachable; log it and let checkout-strategy selection handle the missing commit"],"exampleFix":"// before: zero budget left, fetch refuses to start\nlet outcome = fetch_if_missing(repo, oid, &git, Duration::ZERO)?;\n// after: compute a fresh budget (or retry the whole restore run)\nlet budget = fresh_restore_fetch_budget(); // e.g. deadline - now, minus teardown reserve\nlet outcome = fetch_if_missing(repo, oid, &git, budget)?;","handlingStrategy":"retry","validationCode":"fn fetch_budget_ok(deadline: Instant) -> bool {\n    deadline.saturating_duration_since(Instant::now())\n        > RESTORE_FETCH_TEARDOWN_RESERVE // nonzero time must remain\n}\n// call before fetching: if (!fetch_budget_ok(deadline)) extend_budget_or_defer();","typeGuard":null,"tryCatchPattern":"match fetch_if_missing(repo, oid, &git, remaining(deadline)) {\n    Ok(outcome) => outcome,\n    Err(e) if e.to_string().contains(\"restore fetch budget exhausted\") => {\n        // budget spent: defer this oid to a fresh run or extend the deadline\n        defer_to_next_restore_run(oid);\n        FetchCommitOutcome::SkippedInvalidOid // per API: not necessarily unreachable\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Size the restore fetch budget for your network: slow links/monorepos need larger deadlines","Pre-fetch or fully clone snapshot commits so has_object passes and no budget is spent","Check origin connectivity/latency before restore; flaky networks burn the budget on early fetches","Monitor whether both head and base fetches are needed; restore from snapshots whose commits are already local"],"tags":["git","fetch","timeout","budget","restore"],"backgroundTag":"fetch-budget-exhausted","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}