midudev/autoskills · error · Error

could not resolve HEAD for

Error message

could not resolve HEAD for ${repo}

What it means

After a successful `git ls-remote`, resolveRepoHead parses the output lines for a `<40-hex-sha> HEAD` entry to learn the repo's default branch and commit SHA. If no such line is found (sha stays empty), it throws this error. It means the remote answered but its HEAD symref could not be resolved to a commit.

Solutions

  1. Confirm the repo is not empty (has at least one commit on its default branch)
  2. Run `git ls-remote <url> HEAD` manually and check that a SHA line is printed
  3. Ensure the remote advertises HEAD symrefs (use GitHub or update the hosting/proxy)
  4. Fall back to pinning an explicit branch/SHA instead of relying on HEAD resolution

Example fix

// before
const head = await resolveRepoHead("org/empty-repo"); // throws
// after
const head = await resolveRepoHead("org/skills-repo"); // non-empty repo
Defensive patterns

Strategy: validation

Validate before calling

// verify the repo advertises a resolvable HEAD
const out = execSync(`git ls-remote https://github.com/${repo} HEAD`, { encoding: "utf8" });
if (!/^[0-9a-f]{40}\s+HEAD$/im.test(out)) {
  throw new Error(`${repo} has no resolvable HEAD (empty repo?)`);
}

Try / catch

try {
  const head = await resolveRepoHead(repo);
} catch (err) {
  if (err.message.startsWith("could not resolve HEAD")) {
    console.error(`Repo ${repo} appears empty or HEAD is not advertised`);
    // skip repo or fall back to a pinned branch/sha
  } else throw err;
}

Prevention

When it happens

Trigger: `git ls-remote` output contains no line matching /^([0-9a-f]{40})\s+HEAD$/i — e.g. the remote returns no HEAD entry, output format is unexpected, or the ls-remote invocation didn't include the HEAD ref (odd server configs, empty repos with no commits).

Common situations: Syncing an initialized but completely empty GitHub repo; a git server/proxy that mangles or omits the HEAD symref line; very old or unusual git hosting that doesn't advertise HEAD in ls-remote output.

Related errors


AI-assisted analysis of midudev/autoskills@0ec725320d (2026-09-15). Data as JSON: /api/errors/6807d0bebf298ad7. Report an issue: GitHub.

Appendix: source

Thrown at packages/autoskills/scripts/sync-skills.mjs:192

  );
  if (result.status !== 0) {
    throw new Error(`git ls-remote failed for ${repo}: ${result.stderr.trim() || "unknown error"}`);
  }

  let defaultBranch = "main";
  let sha = "";
  for (const line of result.stdout.split("\n")) {
    const symref = line.match(/^ref:\s+refs\/heads\/(.+)\s+HEAD$/);
    if (symref) {
      defaultBranch = symref[1];
      continue;
    }
    const head = line.match(/^([0-9a-f]{40})\s+HEAD$/i);
    if (head) sha = head[1];
  }

  if (!sha) {
    throw new Error(`could not resolve HEAD for ${repo}`);
  }

  return { defaultBranch, sha };
}

async function resolveRepoInfo(repo) {
  const res = await ghFetch(`https://api.github.com/repos/${repo}`);
  const body = await res.json();
  return {
    sizeKB: body.size || 0,
  };
}

// Tarball download size threshold (KB). Above this we use per-file fetch.
const HEAVY_REPO_KB = 50_000;
// Hard timeout for tarball downloads. Some repos have slow codeload CDNs.
const TARBALL_TIMEOUT_MS = 180_000;

View on GitHub (pinned to 0ec725320d)