xai-org/grok-build · error
unsupported checkout target (need a full commit oid or a sim
Error message
unsupported checkout target (need a full commit oid or a simple git ref): {target} What it means
fetch_checkout_target_if_missing fetches a checkout target from origin only when it can map the target to a safe fetch spec via origin_fetch_spec_for_checkout_target. That mapping accepts full 40/64-hex object ids, simple safe git refs (branch names, refs/heads/…, refs/tags/…), and rewrites local remote-tracking names (origin/foo, refs/remotes/origin/foo) to the remote branch. This error is thrown for anything else: empty strings, targets starting with '-' (option-injection risk), refs containing ':', '*', '?', '[', backslash, whitespace, '..' or '@{', and abbreviated SHAs, which checkout locally but cannot be fetched from origin.
Source
Thrown at crates/codegen/xai-grok-workspace/src/restore_fetch.rs:269
.current_dir(repo)
.args(["cat-file", "-t", spec])
.stdout(Stdio::null())
.stderr(Stdio::null())
.output();
matches!(output, Ok(o) if o.status.success())
}
/// Fetch a checkout target (full oid or simple ref) if it is not already local.
///
/// # Errors
///
/// Unsafe/unsupported spec, spawn failure, timeout, or non-zero git exit.
pub(crate) fn fetch_checkout_target_if_missing(
repo: &Path,
target: &str,
) -> Result<FetchCommitOutcome> {
let Some(spec) = origin_fetch_spec_for_checkout_target(target) else {
bail!("unsupported checkout target (need a full commit oid or a simple git ref): {target}");
};
if is_full_object_id(spec) {
return fetch_commit_if_missing(repo, spec);
}
fetch_refspec_from_origin(repo, spec, RESTORE_FETCH_BUDGET)?;
Ok(FetchCommitOutcome::Fetched)
}
fn is_shallow_repository(repo: &Path) -> bool {
let output = git_command()
.current_dir(repo)
.args(["rev-parse", "--is-shallow-repository"])
.stdout(Stdio::piped())
.stderr(Stdio::null())
.output();
matches!(
output,
Ok(o) if o.status.success() && String::from_utf8_lossy(&o.stdout).trim() == "true"View on GitHub (pinned to bc7f02eddd)
Solutions
- Pass the full 40- or 64-character lowercase hex object id instead of an abbreviated SHA — resolve it with `git rev-parse <sha>` in a repo that has it, or fetch by branch/tag
- Use a simple safe ref (branch name, refs/heads/…, refs/tags/…) as the checkout target instead of a range, wildcard, or rev expression
- Fix the source of the bad target (snapshot manifest / user config) to store full oids or plain ref names; trim stray whitespace and arrow-style log output
- If the commit only exists locally under an abbreviated form, expand it first (`git rev-parse --verify <abbrev>^{commit}`) before requesting a fetch
Example fix
// before: abbreviated SHA cannot be fetched from origin fetch_checkout_target_if_missing(repo, "a1b2c3d")?; // after: resolve to the full oid first let full = git_rev_parse(repo, "a1b2c3d")?; // "a1b2c3d…" (40 hex chars) fetch_checkout_target_if_missing(repo, &full)?;
Defensive patterns
Strategy: validation
Validate before calling
use crate::restore_fetch::{origin_fetch_spec_for_checkout_target, is_full_object_id};
fn checkout_target_fetchable(target: &str) -> bool {
origin_fetch_spec_for_checkout_target(target).is_some()
}
// call before the API: assert!(checkout_target_fetchable(target), "use a full oid or simple ref"); Type guard
fn is_fetchable_checkout_target(target: &str) -> bool {
is_full_object_id(target)
|| (!target.is_empty()
&& !target.starts_with('-')
&& !target.contains([':', '*', '?', '[', '\\', ' ', '\t', '\n', '\r'])
&& !target.contains("..")
&& !target.contains("{"))
} Try / catch
match fetch_checkout_target_if_missing(repo, target) {
Ok(outcome) => outcome,
Err(e) if e.to_string().starts_with("unsupported checkout target") => {
let full = expand_to_full_oid(repo, target) // git rev-parse --verify <target>^{commit}
.context("target must be a full commit oid or simple git ref")?;
fetch_checkout_target_if_missing(repo, &full)?
}
Err(e) => return Err(e),
} Prevention
- Always store full 40/64-char commit oids in manifests and user config, never short SHAs
- Reject ranges, wildcards, and rev expressions at config-parse time
- Trim whitespace and strip log-style prefixes (e.g. 'origin/HEAD -> origin/main') from targets
- Sanity-check targets with origin_fetch_spec_for_checkout_target (or the guard above) before calling restore APIs
When it happens
Trigger: Calling fetch_checkout_target_if_missing with an abbreviated SHA (e.g. 7-char commit prefix); a target with glob/range characters like 'main..other' or 'v1.*'; an empty or dash-prefixed target; a rev expression or log-pasted string (e.g. 'origin/HEAD -> origin/main') that origin_fetch_spec_for_checkout_target maps to None.
Common situations: User config or a snapshot manifest storing an abbreviated commit SHA instead of the full oid; a checkout target recorded as a revision range or wildcard refspec; targets pasted from git logs with arrow-style prefixes; corrupted restore metadata passing empty strings.
Related errors
- refusing unsafe fetch refspec
- {what} must not be empty
- invalid worktree id {:?}
- git fetch origin {oid} skipped: restore fetch budget exhaust
- git fetch --no-tags origin {spec} failed ({status}): {stderr
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/2dacb86090453b90.
Report an issue: GitHub.