{"record":{"id":"7ab3e156d988469d","repo":"golang/go","slug":"s-exists-but-is-not-a-directory-7ab3e1","errorCode":null,"errorMessage":"%s exists but is not a directory","messagePattern":"(.+?) exists but is not a directory","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/codehost/vcs.go","lineNumber":112,"sourceCode":"}\n\nfunc newVCSRepo(ctx context.Context, vcs, remote string, local bool) (Repo, error) {\n\tif vcs == \"git\" {\n\t\treturn newGitRepo(ctx, remote, local)\n\t}\n\tr := &vcsRepo{remote: remote, local: local}\n\tcmd := vcsCmds[vcs]\n\tif cmd == nil {\n\t\treturn nil, fmt.Errorf(\"unknown vcs: %s %s\", vcs, remote)\n\t}\n\tr.cmd = cmd\n\tif local {\n\t\tinfo, err := os.Stat(remote)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !info.IsDir() {\n\t\t\treturn nil, fmt.Errorf(\"%s exists but is not a directory\", remote)\n\t\t}\n\t\tr.dir = remote\n\t\tr.mu.Path = r.dir + \".lock\"\n\t\treturn r, nil\n\t}\n\tif !strings.Contains(remote, \"://\") {\n\t\treturn nil, fmt.Errorf(\"invalid vcs remote: %s %s\", vcs, remote)\n\t}\n\tvar err error\n\tr.dir, r.mu.Path, err = WorkDir(ctx, vcsWorkDirType+vcs, r.remote)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif cmd.init == nil {\n\t\treturn r, nil\n\t}\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/codehost/vcs.go#L94-L130","documentation":"In local mode, newVCSRepo os.Stats the remote path and requires it to be a directory. If the path exists but is a regular file (or symlink to a file, socket, etc.), this error fires. The %s is the remote path string.","triggerScenarios":"newVCSRepo called with local==true and remote pointing at a non-directory filesystem entry — e.g. a file path, a stale lock file, or a symlink to a file.","commonSituations":"Passing a file path instead of a repo directory to a local-mode codehost constructor; a misconfigured GOFLAGS or replace directive that resolves to a file; a leftover `.lock` or tarball where a working copy was expected.","solutions":["Point the local-mode path at the actual repository working directory (the folder containing the .hg/.svn/.fossil metadata).","If using a replace directive, ensure the target is a directory: `replace example.org/m => ./local/m` not a file.","Remove the stale file at the path and clone the repo there properly."],"exampleFix":"// before\nreplace example.org/m => ./local/m.tar\n// error: ./local/m.tar exists but is not a directory\n\n// after — extract or clone to a directory\nreplace example.org/m => ./local/m","handlingStrategy":"validation","validationCode":"func isLocalRepoDir(path string) bool {\n    info, err := os.Stat(path)\n    return err == nil && info.IsDir()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Double-check replace directives point at directories, not files.","Add a pre-flight `os.Stat` + `IsDir` check in any tool that constructs a local-mode codehost.Repo."],"tags":["vcs","local-mode","filesystem","configuration"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}