can1357/oh-my-pi · error · RuntimeError
git cat-file returned {len(lines)} lines, expected {len(CACH
Error message
git cat-file returned {len(lines)} lines, expected {len(CACHE_KEY_PATHS)}: {proc.stdout!r} What it means
`compute_key()` builds a deterministic sha256 cache key by piping `HEAD:<path>` requests for every entry of CACHE_KEY_PATHS ('crates', 'Cargo.lock', 'Cargo.toml', 'rust-toolchain.toml', 'packages/natives') into one `git cat-file --batch-check` invocation. It asserts the batch output contains exactly one line per requested path; if git returns fewer (or more) lines, the parse would silently misalign path-to-hash pairs, so a RuntimeError is raised with the raw stdout for diagnosis.
Source
Thrown at python/robomp/src/natives_cache.py:159
Raises ``subprocess.CalledProcessError`` if ``git`` itself fails (e.g.
not a repo) — callers SHOULD treat that as "no cache" and proceed.
"""
tgt = target if target is not None else target_triple()
stdin = "".join(f"HEAD:{p}\n" for p in CACHE_KEY_PATHS)
proc = subprocess.run(
["git", "cat-file", "--batch-check"],
input=stdin,
cwd=str(repo_dir),
text=True,
capture_output=True,
check=True,
env=_git_safe_directory_env(repo_dir),
timeout=120.0,
)
lines = proc.stdout.splitlines()
if len(lines) != len(CACHE_KEY_PATHS):
raise RuntimeError(
f"git cat-file returned {len(lines)} lines, expected {len(CACHE_KEY_PATHS)}: {proc.stdout!r}"
)
h = hashlib.sha256()
for path, line in zip(CACHE_KEY_PATHS, lines, strict=True):
stripped = line.strip()
if stripped.endswith("missing"):
tree_hash = _NULL_TREE_HASH
else:
# "<hash> <type> <size>" — take the first token as the tree/blob hash.
tree_hash = stripped.split(None, 1)[0]
h.update(f"{path}\t{tree_hash}\n".encode())
h.update(f"TARGET\t{tgt}\n".encode())
return h.hexdigest()
def _repo_slug(repo: str) -> str:
"""Same convention as ``SandboxManager.pool_path``."""
return repo.replace("/", "__")View on GitHub (pinned to 9690622007)
Solutions
- Inspect the `proc.stdout` echoed in the message to see which lines came back and which path line is missing or extra
- Reproduce manually in the repo: `printf 'HEAD:crates\nHEAD:Cargo.lock\nHEAD:Cargo.toml\nHEAD:rust-toolchain.toml\nHEAD:packages/natives\n' | git cat-file --batch-check` and compare line count to 5
- Check the repo is a normal full clone with the expected monorepo layout; re-clone without --filter/--sparse if needed
- Verify the git version matches the one used in CI/Docker (the pi image pins its toolchain)
- Catch the RuntimeError at the call site and treat it as 'no cache', proceeding with a normal build — the documented fallback posture for compute_key failures
Example fix
# before
key = compute_key(workspace_repo)
entry = cache.lookup(repo, key)
# after
try:
key = compute_key(workspace_repo)
except (RuntimeError, subprocess.CalledProcessError, subprocess.TimeoutExpired):
key = None # no cache; proceed with a normal build
entry = cache.lookup(repo, key) if key else None Defensive patterns
Strategy: try-catch
Validate before calling
def repo_supports_cache_key(repo_dir):
# Missing paths are tolerated (null hash); the guard is that git works and the layout matches
out = subprocess.run(["git", "rev-parse", "--is-inside-work-tree"], cwd=repo_dir, capture_output=True)
return out.returncode == 0 and not (Path(repo_dir) / ".git").is_file() # avoid sparse/worktree edge cases Type guard
def cat_file_output_well_formed(stdout: str, expected: int) -> bool:
return len(stdout.splitlines()) == expected Try / catch
try:
key = compute_key(repo_dir)
except (RuntimeError, subprocess.CalledProcessError, subprocess.TimeoutExpired):
key = None # treat as cache miss and do a normal build Prevention
- Use a standard full clone (not sparse/partial) of the monorepo before invoking compute_key
- Pin and verify the git version in the runtime image; smoke-test `git cat-file --batch-check` on the repo at startup
- Always catch RuntimeError plus CalledProcessError/TimeoutExpired around compute_key and fall back to a cache miss
- Keep the proc.stdout echoed in the message when reporting so misalignment is diagnosable
When it happens
Trigger: Calling `compute_key(repo_dir)` (directly or via the NativesCache capture/populate flow) where `git cat-file --batch-check` does not emit exactly len(CACHE_KEY_PATHS)=5 lines: git aborts writing on one line early, a sparse/partial clone suppresses object lines, a git hook/config/filter alters batch-check output, or a fake git stub in tests emits truncated stdout. Called by tests like test_compute_key_deterministic_across_clones and test_capture_then_populate_shares_node_inode_but_copies_companions.
Common situations: Running against a shallow or partial (blobless) clone; a sparse-checkout worktree where `HEAD:crates` resolves unexpectedly; an old or patched git version in the runtime image whose batch-check formatting differs; a replace-ref or filter config changing output; a race where HEAD changes mid-invocation.
Related errors
- git timed out after {effective_timeout:.0f}s: {' '.join(_red
- GitCommandError(cmd, proc.returncode, proc.stdout, proc.stde
- GitCommandError(["git", *args], proc.returncode, proc.stdout
- timeout reading origin url
- GitCommandError: git branch -m failed (nonzero exit)
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0e8b3102d0be49a3.
Report an issue: GitHub.