golang/go · error

%s exists but is not a directory

Error message

%s exists but is not a directory

What it means

Thrown by newGitRepo in local mode when os.Stat(remote) succeeds (the path exists) but info.IsDir() is false — the 'remote' is a regular file, not a git checkout directory. A local git repository must be a directory.

Source

Thrown at src/cmd/go/internal/modfetch/codehost/git.go:59

}

func (e notExistError) Error() string   { return e.err.Error() }
func (notExistError) Is(err error) bool { return err == fs.ErrNotExist }

const gitWorkDirType = "git3"

func newGitRepo(ctx context.Context, remote string, local bool) (Repo, error) {
	r := &gitRepo{remote: remote, local: local}
	if local {
		if strings.Contains(remote, "://") { // Local flag, but URL provided
			return nil, fmt.Errorf("git remote (%s) lookup disabled", remote)
		}
		info, err := os.Stat(remote)
		if err != nil {
			return nil, err
		}
		if !info.IsDir() {
			return nil, fmt.Errorf("%s exists but is not a directory", remote)
		}
		r.dir = remote
		r.mu.Path = r.dir + ".lock"
		r.sha256Hashes = r.checkConfigSHA256(ctx)
		return r, nil
	}
	// This is a remote path lookup.
	if !strings.Contains(remote, "://") { // No URL scheme, could be host:path
		if strings.Contains(remote, ":") {
			return nil, fmt.Errorf("git remote (%s) must not be local directory (use URL syntax not host:path syntax)", remote)
		}
		return nil, fmt.Errorf("git remote (%s) must not be local directory", remote)
	}
	var err error
	r.dir, r.mu.Path, err = WorkDir(ctx, gitWorkDirType, r.remote)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Verify the path: 'ls -la <remote>' and confirm it is a directory.
  2. Update the replace directive or path to point at the actual git working directory.
  3. If you meant a remote URL, use URL syntax instead of a local path.
  4. Extract the archive if the source was downloaded as a tarball.

Example fix

# before (go.mod)
replace example.com/mod => ./mod.tar.gz
# after
mkdir -p ./mod && tar -xzf mod.tar.gz -C ./mod
replace example.com/mod => ./mod
Defensive patterns

Strategy: validation

Validate before calling

func validateLocalRepoPath(path string) error {
    fi, err := os.Stat(path)
    if err != nil { return err }
    if !fi.IsDir() {
        return fmt.Errorf("%q exists but is not a directory", path)
    }
    return nil
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: newGitRepo(ctx, remote, local=true) where remote is a path to a file (e.g. a tarball, a .git pack file, or any non-directory) rather than a working tree or bare repo directory.

Common situations: A replace directive pointing at a file instead of a directory; a path that was a directory but got replaced by an archive; a typo in the path resolving to a nearby file.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/a261361285bcdcaa. Report an issue: GitHub.