Hmbown/CodeWhale · error · Error
Annotated tag did not peel to a commit SHA
Error message
Annotated tag ${tag} did not peel to a commit SHA What it means
resolveTagCommitSha verifies a GitHub tag ref points at a commit. If the ref points at an annotated tag object, the script fetches the tag object via /git/tags/<sha> and expects it to peel to a commit. This error means the annotated tag object's inner object is missing, not of type 'commit', or lacks a sha, so the tag cannot be resolved to a commit.
Solutions
- Inspect the tag with `gh api repos/<repo>/git/tags/<sha>` and confirm object.type is 'commit'.
- Recreate the tag on the intended commit: `git tag -f -a <tag> <commit> && git push -f origin <tag>`.
- If the tag points at another tag, peel one level or re-tag directly against the commit.
Example fix
// before: tag created against wrong target git tag -a v1.0.0 refs/heads/other // after git tag -f -a v1.0.0 <commit-sha> && git push -f origin v1.0.0
Defensive patterns
Strategy: validation
Validate before calling
const ref = await githubApi(repo, `/git/tags/...`); if (ref.object?.type !== "commit") throw new Error("tag must peel to a commit before verify"); Type guard
function peelsToCommit(tagObject) { return !!tagObject?.object && tagObject.object.type === "commit" && typeof tagObject.object.sha === "string" && tagObject.object.sha.length > 0; } Try / catch
try { const sha = await resolveTagCommitSha(repo, tag); } catch (e) { if (e.message.includes("did not peel")) { console.error(`Re-tag ${tag} against a commit`); process.exit(1); } throw e; } Prevention
- Always create release tags with `git tag -a <tag> <commit>`
- Verify tags with `gh api repos/<repo>/git/refs/tags/<tag>` before publishing
- Never point annotated tags at other tags or non-commit objects
When it happens
Trigger: A GitHub tag ref resolves to an annotated tag whose /git/tags payload has object.type != 'commit' (e.g. the tag points at a tree or blob), has no nested object, or no sha — typically a malformed or hand-crafted tag object.
Common situations: Re-tagging a release manually with a malformed annotated tag; a CI step creating tags with wrong target; API drift where the tag object references another tag or non-commit object.
Related errors
- GitHub tag ref did not include an object SHA
- GitHub tag ref points at , not a commit or annotated tag
- A full Git history is required to establish the PR merge…
- baseline provenance must identify a clean source tree
- baseline provenance needs an exact source SHA
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/42ded6490fe50016.
Report an issue: GitHub.
Appendix: source
Thrown at npm/codewhale/scripts/verify-release-assets.js:212
async function githubApi(repo, path) {
return downloadJson(githubApiUrl(repo, path));
}
async function resolveTagCommitSha(repo, tag) {
const ref = await githubApi(repo, `/git/ref/tags/${encodeURIComponent(tag)}`);
if (!ref.object || !ref.object.sha || !ref.object.type) {
throw new Error(`GitHub tag ref ${tag} did not include an object SHA`);
}
if (ref.object.type === "commit") {
return ref.object.sha;
}
if (ref.object.type !== "tag") {
throw new Error(`GitHub tag ref ${tag} points at ${ref.object.type}, not a commit or annotated tag`);
}
const tagObject = await githubApi(repo, `/git/tags/${ref.object.sha}`);
if (!tagObject.object || tagObject.object.type !== "commit" || !tagObject.object.sha) {
throw new Error(`Annotated tag ${tag} did not peel to a commit SHA`);
}
return tagObject.object.sha;
}
async function findReleaseWorkflowRun(repo, tag, tagSha, api = githubApi) {
const runs = await api(repo, "/actions/workflows/release.yml/runs?per_page=100");
const candidates = (runs.workflow_runs || [])
.filter((run) => run.head_sha === tagSha)
.filter((run) => run.event === "push" || run.event === "workflow_dispatch")
.sort((a, b) => String(b.updated_at).localeCompare(String(a.updated_at)));
const orderedCandidates = [
...candidates.filter((run) => run.head_branch === tag),
...candidates.filter((run) => run.head_branch !== tag),
];
for (const candidate of orderedCandidates) {
const runId = candidate.database_id || candidate.id;
if (!runId) {View on GitHub (pinned to 433685b202)