abhigyanpatwari/GitNexus · error · ValueError
task {task['id']} did not resolve to an immutable commit
Error message
task {task['id']} did not resolve to an immutable commit What it means
Raised by resolve_task_bindings when resolved_sha does not match `[0-9a-fA-F]{40,64}` (runner_tasks.py:137-138). This covers both the freshly-resolved ref path and the supplied-pin path: the value must be a raw git object id (40-char SHA-1 or 64-char SHA-256), not a ref name, abbreviated id, or empty string.
Source
Thrown at eval/workflow_bench/runner_tasks.py:138
repo_identity = Path(repo_output).resolve()
if expected is None:
resolved_sha = run_checked(
[
"git",
"-C",
str(repo_identity),
"rev-parse",
f"{task.get('ref', 'HEAD')}^{{commit}}",
],
timeout=60,
).stdout_tail.strip()
else:
supplied = expected[index]
if not isinstance(supplied, dict):
raise ValueError(f"task binding {index} must be an object")
resolved_sha = str(supplied.get("resolved_sha", ""))
if not re.fullmatch(r"[0-9a-fA-F]{40,64}", resolved_sha):
raise ValueError(f"task {task['id']} did not resolve to an immutable commit")
exists = run_managed(
["git", "-C", str(repo_identity), "cat-file", "-e", f"{resolved_sha}^{{commit}}"],
timeout=60,
)
if not exists.ok:
raise ValueError(f"pinned task commit is unavailable for {task['id']}: {resolved_sha}")
if task_asset_cache is None:
dependency_binding = capture_task_dependency_binding(
task,
repo=repo_identity,
resolved_sha=resolved_sha.lower(),
)
else:
dependency_binding = task_asset_cache.prepare(
task,
repo=repo_identity,
resolved_sha=resolved_sha.lower(),
).dependency_bindingView on GitHub (pinned to d540b00184)
Solutions
- Confirm the repo/ref resolves to a real commit: `git -C <repo> rev-parse <ref>^{commit}`.
- If using a pin, ensure resolved_sha is the full 40-char (or 64-char) object id.
- For an unborn/empty repo, point ref at an existing commit first.
Example fix
// before pin: {"resolved_sha": "abc1234"}
// after pin: {"resolved_sha": "abc1234567890abcdef0123456789abcdef0123456"} Defensive patterns
Strategy: validation
Validate before calling
import subprocess, re
sha = subprocess.check_output(
["git", "-C", repo, "rev-parse", f"{ref}^{{commit}}"], text=True
).strip()
if not re.fullmatch(r"[0-9a-fA-F]{40,64}", sha):
raise SystemExit(f"ref did not resolve to a commit object: {sha!r}") Type guard
import re
def is_full_object_id(sha: str) -> bool:
return bool(re.fullmatch(r"[0-9a-fA-F]{40,64}", sha)) Try / catch
try:
bindings = resolve_task_bindings(tasks, expected)
except ValueError as exc:
if "did not resolve to an immutable commit" in str(exc):
# regenerate pin from a resolvable ref
expected = None
bindings = resolve_task_bindings(tasks, expected)
else:
raise Prevention
- Pin full 40/64-char object ids, never abbreviated SHAs or branch names.
- Resolve refs with `git rev-parse <ref>^{commit}` and store the result.
When it happens
Trigger: `git rev-parse <ref>^{commit}` returned empty or a symbolic ref (e.g. because the ref is ambiguous/unborn); a supplied pin's resolved_sha is an abbreviated id, a branch name, or missing; the pin JSON has a typo.
Common situations: Pointing ref at an empty repo; using a 7-char short SHA in the pin; the rev-parse failed silently and left resolved_sha blank.
Related errors
- task binding count does not match selected tasks
- pinned task commit is unavailable for {task['id']}: {resolve
- task binding definition drifted for {task['id']}
- candidate overlay is byte-identical to the incumbent skills
- managed command failed ({result.state}, exit={result.returnc
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/76f72db6ab446e42.
Report an issue: GitHub.