gastownhall/beads · error

not a git repository: %w

Error message

not a git repository: %w

What it means

After obtaining the hostname, GetCloneIDForPath resolves the main repository root with mainRepoRootForPath (using --git-common-dir so worktrees share a clone ID, GH#2867). If that resolution fails, the error is wrapped as "not a git repository" — the given path is not inside a git work tree or the git command could not run.

Source

Thrown at internal/beads/fingerprint.go:160

// GetCloneID generates a unique ID for this specific clone (not shared with other clones)
func GetCloneID() (string, error) {
	return GetCloneIDForPath("")
}

// GetCloneIDForPath generates a unique ID for the specific clone rooted at or
// containing repoPath. An empty repoPath uses the current cwd.
//
// GH#2867: Uses the main repo root (not worktree root) so that all worktrees
// sharing a database produce the same clone ID.
func GetCloneIDForPath(repoPath string) (string, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return "", fmt.Errorf("failed to get hostname: %w", err)
	}

	repoRoot, err := mainRepoRootForPath(repoPath)
	if err != nil {
		return "", fmt.Errorf("not a git repository: %w", err)
	}

	normalizedPath := normalizedRepoPath(repoRoot)
	hash := sha256.Sum256([]byte(hostname + ":" + normalizedPath))
	return hex.EncodeToString(hash[:8]), nil
}

func runGitInRepo(repoPath string, args ...string) ([]byte, error) {
	cmd := exec.Command("git", args...)
	if repoPath != "" {
		cmd.Dir = repoPath
	}
	return cmd.Output()
}

// mainRepoRootForPath returns the main repository root for a given path,
// correctly handling git worktrees. For worktrees, this returns the parent
// of --git-common-dir (the main repo root), not --show-toplevel (the

View on GitHub (pinned to 71377f2769)

Solutions

  1. Verify with `git -C <path> rev-parse --show-toplevel`; if it fails, run `git init` or clone the repo first
  2. Pass the correct repository path to GetCloneIDForPath
  3. Ensure git is installed and on PATH (`which git`)
  4. Restore a missing .git directory or re-clone

Example fix

// before
cloneID, err := beads.GetCloneIDForPath("/tmp/scratch")
// after
cloneID, err := beads.GetCloneIDForPath("/home/me/project") // inside a git repo
Defensive patterns

Strategy: validation

Validate before calling

if out, err := exec.Command("git", "-C", path, "rev-parse", "--is-inside-work-tree").Output(); err != nil || strings.TrimSpace(string(out)) != "true" {
    // not a repo; init or clone before calling
}

Try / catch

cloneID, err := beads.GetCloneIDForPath(path)
if err != nil && strings.Contains(err.Error(), "not a git repository") {
    return fmt.Errorf("initialize the repo first: %w", err)
}

Prevention

When it happens

Trigger: Calling GetCloneID/GetCloneIDForPath with a repoPath outside any git repository, a deleted .git directory, or a path where `git rev-parse --show-toplevel --git-common-dir` exits non-zero (e.g. git binary missing or path unreadable).

Common situations: Pointing bd at a plain folder (notes, dotfiles dir without git); running before `git clone`/`git init` completed; typo'd path; git not installed or PATH broken so the exec fails.

Related errors


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