tailscale/tailscale · error

finding git root: %w

Error message

finding git root: %w

What it means

mkversion.InfoFrom runs `git rev-parse --show-toplevel` in the directory you pass (empty string = cwd) to locate the git checkout it derives version strings from. This error means that command failed: the directory is not inside a git work tree, the .git directory is corrupt, or git could not run at all. The wrapped error (usually a dirRunner 'running [git rev-parse --show-toplevel]...' message) carries git's own 'fatal: not a git repository' diagnostics.

Source

Thrown at version/mkversion/mkversion.go:122

}

// Info constructs a VersionInfo from the current working directory and returns
// it, or terminates the process via log.Fatal.
func Info() VersionInfo {
	v, err := InfoFrom("")
	if err != nil {
		log.Fatal(err)
	}
	return v
}

// InfoFrom constructs a VersionInfo from dir and returns it, or an error.
func InfoFrom(dir string) (VersionInfo, error) {
	runner := dirRunner(dir)

	gitRoot, err := runner.output("git", "rev-parse", "--show-toplevel")
	if err != nil {
		return VersionInfo{}, fmt.Errorf("finding git root: %w", err)
	}
	runner = dirRunner(gitRoot)

	modBs, err := os.ReadFile(filepath.Join(gitRoot, "go.mod"))
	if err != nil {
		return VersionInfo{}, fmt.Errorf("reading go.mod: %w", err)
	}
	modPath := modfile.ModulePath(modBs)

	if modPath == "" {
		return VersionInfo{}, fmt.Errorf("no module path in go.mod")
	}
	if modPath == "tailscale.com" {
		// Invoked in the tailscale.com repo directly, just no further info to
		// collect.
		v, err := infoFromDir(gitRoot)
		if err != nil {
			return VersionInfo{}, err

View on GitHub (pinned to 6e0912f979)

Solutions

  1. Run the build from the root of a git clone and verify with `git rev-parse --show-toplevel` that it prints the expected path
  2. If git is not installed (see a 'running [git ...]' wrapper mentioning exec/not-found), install git and ensure it is on PATH
  3. Repair the checkout: confirm `git status` works; if .git is corrupt, re-clone
  4. Pass a directory that is actually inside the repository instead of a temp/output directory

Example fix

# before: building from an unpacked tarball
mkversion.InfoFrom("/build/tailscale-src")   # no .git -> finding git root: ...

# after: build from a real clone
$ git clone https://github.com/tailscale/tailscale /build/tailscale
mkversion.InfoFrom("/build/tailscale")
Defensive patterns

Strategy: validation

Validate before calling

// Verify dir is inside a git work tree before calling mkversion.InfoFrom.
func inGitRepo(dir string) bool {
	cmd := exec.Command("git", "-C", dir, "rev-parse", "--show-toplevel")
	return cmd.Run() == nil
}

if !inGitRepo(buildDir) {
	log.Fatalf("%s is not a git checkout; run the build from a clone", buildDir)
}
v, err := mkversion.InfoFrom(buildDir)

Type guard

func isGitRootError(err error) bool {
	return err != nil && strings.Contains(err.Error(), "finding git root:")
}

Try / catch

v, err := mkversion.InfoFrom(dir)
if err != nil {
	if isGitRootError(err) {
		log.Fatalf("run the build from a git checkout: %v", err)
	}
	return fmt.Errorf("mkversion: %w", err)
}

Prevention

When it happens

Trigger: Calling mkversion.Info() or InfoFrom(dir) with dir outside any git repository, with a broken/missing .git directory, or in an environment where the git binary is missing from PATH (surfaced via the 2076-style 'running %v' wrapper).

Common situations: Running the tailscale build/version-stamping step from an exported source tarball, from the wrong directory in CI, or inside a minimal container that lacks git or has HOME unset so git cannot be found.

Related errors


AI-assisted analysis of tailscale/tailscale@6e0912f979 (2026-08-18). Data as JSON: /api/errors/40390e8825c65215. Report an issue: GitHub.