Skip to content

Install: show invalid ref and pin errors instead of Unknown error - #357

Merged
Minitour merged 2 commits into
developfrom
fix/git-ref-errors-shown
Oct 23, 2026
Merged

Minitour merged 2 commits into
developfrom
fix/git-ref-errors-shown

Conversation

@Minitour

@Minitour Minitour commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

Found while verifying the v2.4.0 release (#351) locally. The ref checks from #317 and the lockfile pin check from #352 throw clear errors, but install showed Failed to clone <url>: Unknown error instead. On GitHub and GitLab, a missing tag or pinned commit was also reported as "repository not accessible".

What changed

  • explainGitError (install-tasks/helpers/git.ts) rewrote every error it got. Errors without a fatal: / error: line became "Unknown error", and on GitHub/GitLab anything containing "not found" became "repository not accessible". Capa's own cache errors (invalid ref or pin, missing tag or commit, tampered mirror) now pass through as they are. Only an error from running git is explained. git() in shared/cache/git-cli.ts, which runs every git command in the cache, records the errors it rejects with, and isGitProcessError checks that. This doesn't rely on the shape of the error, which differs between runtimes and platforms.
  • The generic-git branch's prefix check for "Tag/branch / Commit / Pinned commit" is covered by the new rule, so it's removed.

Screenshots / logs

Release build, before and after:

Case Before After
version: main@{1} Failed to clone https://github.com/…: Unknown error Invalid version "main@{1}": use a tag, branch or commit SHA (…)
resolvedRef: main in capabilities.lock Failed to clone https://github.com/…: Unknown error Invalid pinned commit "main" in capabilities.lock: expected a commit SHA. Remove the entry or run "capa install --no-cache" to re-pin.
GitHub plugin with version: v99.99.99 GitHub repository not accessible: … Tag/branch "v99.99.99" not found in repository at …

Test plan

  • New tests: the cache's messages come through unchanged for github and git (this fails without the fix); errors that come out of git() (a failed command, and git missing) are still explained.
  • CI runs the tests on Linux, macOS and Windows.
  • Re-ran all three cases above against a release build, plus an unreachable host, which is still explained as a network error.
  • bunx tsc --noEmit; CLI and shared suites have no assertion failures (only the known Windows EBUSY/EPERM temp cleanup).

Checklist

  • Tests added or updated
  • bunx tsc --noEmit passes
  • Docs updated (if user-facing): not needed

🤖 Generated with Claude Code

explainGitError rewrote every error. Invalid refs and lockfile pins
came out as 'Failed to clone ...: Unknown error', and a missing tag on
GitHub/GitLab as 'repository not accessible'. Only a failed git process
(cmd / code set) is explained now; capa's own messages pass through.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Preserve actionable git ref and lockfile pin errors during install

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Show cache-generated invalid ref, pin, and missing tag errors instead of misleading clone errors.
• Explain failed git processes and missing git binaries as before.
• Add regression tests for both error paths.
Diagram

graph TD
  Cache["Cache or git failure"] --> Snapshot["Snapshot wrapper"] --> Classify{"Git process?"} -->|No| Original["Original error"] --> Install["Install output"]
  Classify -->|Yes| Explain["Git error explainer"] --> Install
Loading
High-Level Assessment

Keep the metadata-based distinction: it preserves cache errors without maintaining a list of message prefixes, while retaining explanations for git-process failures. A prefix-based exception was considered but would need updates for each new cache error.

Files changed (2) +26 / -6

Bug fix (1) +4 / -5
git.tsPass through cache errors before classifying git failures +4/-5

Pass through cache errors before classifying git failures

• Returns Error instances without cmd or code unchanged, preventing cache-generated messages from becoming unknown clone or repository-access errors. Removes the narrower generic-git message-prefix exception, now covered by the shared check.

src/cli/commands/install-tasks/helpers/git.ts

Tests (1) +22 / -1
git.test.tsCover preserved cache errors and explained git failures +22/-1

Cover preserved cache errors and explained git failures

• Adds cases for invalid refs, invalid pins, and missing tags on GitHub and generic git. Verifies that failed git commands and a missing git binary still receive explanatory messages.

src/cli/commands/install-tasks/helpers/tests/git.test.ts

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Cache failures look like clone errors ✓ Resolved
Description
explainGitError treats any Error with a code property as a failed Git process. Filesystem
failures from cache setup or snapshot materialization therefore get rewritten as clone failures,
often hiding the actual permission, disk, or path problem.
Code

src/cli/commands/install-tasks/helpers/git.ts[R81-84]

+  // The cache's own errors (an invalid ref or pin, a missing tag or commit)
+  // already name the cause. Only a failed git process (execFile sets `cmd`,
+  // a spawn failure sets `code`) needs explaining.
+  if (error instanceof Error && !('cmd' in error) && !('code' in error)) return error;
Evidence
getRepoSnapshot sends every cache failure to explainGitError. Cache setup and snapshot
materialization perform filesystem operations that can throw coded errors, and those errors are
rethrown before reaching the helper; the helper then classifies the generic code property as
evidence of a Git process failure and falls back to a clone message when no Git diagnostic is
present.

src/cli/commands/install-tasks/helpers/git.ts[81-100]
src/cli/commands/install-tasks/helpers/repo-snapshot.ts[26-30]
src/shared/cache/snapshot.ts[31-36]
src/shared/cache/snapshot.ts[72-82]
src/shared/cache/git-cli.ts[65-81]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`explainGitError` uses the presence of a generic `code` property to identify child-process failures, but Node filesystem errors also carry `code`. Cache filesystem failures can consequently be rewritten as misleading Git clone errors.
## Fix Focus Areas
- src/cli/commands/install-tasks/helpers/git.ts[81-84]
- src/shared/cache/git-cli.ts[65-81]
## Recommended Fix
Use an explicit child-process error predicate or marker that distinguishes `execFile` failures from arbitrary coded errors, while preserving cache and filesystem errors unchanged. Keep the existing handling for genuine Git spawn failures such as `ENOENT` and command failures carrying `cmd`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/cli/commands/install-tasks/helpers/git.ts Outdated
explainGitError told git failures from capa's own errors by the cmd /
code properties execFile sets. That shape depends on the runtime, so
git() now records the errors it rejects with and the wrapper checks that.
@Minitour
Minitour merged commit fe2e440 into develop Oct 23, 2026
8 checks passed
@Minitour
Minitour deleted the fix/git-ref-errors-shown branch October 23, 2026 15:22
@Minitour Minitour mentioned this pull request Oct 23, 2026
8 of 9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant