gastownhall/beads · error

failed to canonicalize URL: %w

Error message

failed to canonicalize URL: %w

What it means

After obtaining the repository's remote URL from git, ComputeRepoIDForPathWithSource canonicalizes it (normalizing scheme, host, port, .git suffix etc.) before hashing. If canonicalizeGitURL fails, the remote URL cannot be parsed into a usable form and this wrapped error is returned, aborting remote-based fingerprinting.

Source

Thrown at internal/beads/fingerprint.go:70

	output, err := runGitInRepo(repoPath, "config", "--get", "remote.origin.url")
	if err != nil {
		// No remote configured — fall back to path-based fingerprint.
		// Use --git-common-dir to derive the main repo root so that
		// worktrees produce the same fingerprint as the main checkout.
		repoRoot, rootErr := mainRepoRootForPath(repoPath)
		if rootErr != nil {
			return "", "", fmt.Errorf("not a git repository")
		}

		normalized := normalizedRepoPath(repoRoot)
		hash := sha256.Sum256([]byte(normalized))
		return hex.EncodeToString(hash[:16]), RepoIDSourcePath, nil
	}

	repoURL := strings.TrimSpace(string(output))
	canonical, err := canonicalizeGitURL(repoURL)
	if err != nil {
		return "", "", fmt.Errorf("failed to canonicalize URL: %w", err)
	}

	hash := sha256.Sum256([]byte(canonical))
	return hex.EncodeToString(hash[:16]), RepoIDSourceRemote, nil
}

func canonicalizeGitURL(rawURL string) (string, error) {
	rawURL = strings.TrimSpace(rawURL)

	if strings.Contains(rawURL, "://") {
		u, err := url.Parse(rawURL)
		if err != nil {
			return "", fmt.Errorf("invalid URL: %w", err)
		}

		host := strings.ToLower(u.Hostname())
		if port := u.Port(); port != "" && port != "22" && port != "80" && port != "443" {
			host = host + ":" + port

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the remote URL (`git remote -v`) and fix malformed entries in .git/config
  2. Re-set the remote: `git remote set-url origin <correct-url>`
  3. If the URL is valid but unsupported, normalize it to a standard https:// or git@host:path form
  4. As a workaround, ensure a clean remote is configured so path-based fallback is not needed

Example fix

// before (.git/config)
[remote "origin"] url = https:/github.com/acme/repo
// after
git remote set-url origin https://github.com/acme/repo.git
Defensive patterns

Strategy: validation

Validate before calling

out, _ := exec.Command("git", "remote", "get-url", "origin").Output()
u := strings.TrimSpace(string(out))
if u != "" && !strings.Contains(u, "://") && !strings.Contains(u, ":") {
    // fix remote before computing repo id
}

Try / catch

id, err := beads.ComputeRepoIDForPath(path)
if err != nil && strings.Contains(err.Error(), "failed to canonicalize URL") {
    return fmt.Errorf("fix remote: git remote set-url origin <url>: %w", err)
}

Prevention

When it happens

Trigger: Calling ComputeRepoIDForPath on a repo whose `git remote get-url` output cannot be canonicalized — e.g. a malformed remote URL, an unparsable scheme, or unusual output from a insteadOf rewrite that canonicalizeGitURL rejects.

Common situations: Hand-edited .git/config with a broken URL; exotic remote helpers (e.g. `ext::` or credential-helper rewritten URLs); typos like `https:/host/repo` (single slash); corporate proxies injecting non-URL values into the remote.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/68e1c2b6aa604b8f. Report an issue: GitHub.