golang/go · error
replacement directory %s does not exist
Error message
replacement directory %s does not exist
What it means
A go.mod 'replace' directive points the module at a local filesystem directory, but fsys.Stat reports os.ErrNotExist for that directory. The check exists because dirInModule silently treats missing modules as empty, so without it the later failure would be opaque. The error is wrapped via module.VersionError so it carries the module version identity.
Source
Thrown at src/cmd/go/internal/modload/import.go:809
if r := Replacement(ld, mod); r.Path != "" {
if r.Version == "" {
dir = r.Path
if !filepath.IsAbs(dir) {
dir = filepath.Join(replaceRelativeTo(ld), dir)
}
// Ensure that the replacement directory actually exists:
// dirInModule does not report errors for missing modules,
// so if we don't report the error now, later failures will be
// very mysterious.
if _, err := fsys.Stat(dir); err != nil {
// TODO(bcmills): We should also read dir/go.mod here and check its Go version,
// and return a gover.TooNewError if appropriate.
if os.IsNotExist(err) {
// Semantically the module version itself “exists” — we just don't
// have its source code. Remove the equivalence to os.ErrNotExist,
// and make the message more concise while we're at it.
err = fmt.Errorf("replacement directory %s does not exist", r.Path)
} else {
err = fmt.Errorf("replacement directory %s: %w", r.Path, err)
}
return dir, true, module.VersionError(mod, err)
}
return dir, true, nil
}
mod = r
}
if mustHaveSums(ld) && !modfetch.HaveSum(ld.Fetcher(), mod) {
return "", false, module.VersionError(mod, &sumMissingError{})
}
dir, err = ld.Fetcher().Download(ctx, mod)
return dir, false, err
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Create the missing directory and ensure it has a go.mod with the expected module path.
- Fix the replace path in go.mod to point at the correct relative or absolute location.
- Remove or comment out the replace directive if the local override is no longer needed.
- If the directory should come from another repo/branch, fetch it first or switch to a versioned replace (=> example.com/foo v1.2.3).
Example fix
// before (go.mod) replace example.com/foo => ./internal/foo // ./internal/foo absent // error: replacement directory ./internal/foo does not exist // after mkdir -p internal/foo cat > internal/foo/go.mod <<EOF module example.com/foo go 1.22 EOF
Defensive patterns
Strategy: validation
Validate before calling
// Validate every local replace target exists before building.
data, _ := os.ReadFile("go.mod")
f, _ := modfile.Parse("go.mod", data, nil)
for _, r := range f.Replace {
if r.New.Version == "" { // local directory replace
if _, err := os.Stat(r.New.Path); os.IsNotExist(err) {
return fmt.Errorf("replace target missing: %s", r.New.Path)
}
}
} Try / catch
out, err := exec.Command("go", "build", "./...").CombinedOutput()
if err != nil && bytes.Contains(out, []byte("replacement directory") && bytes.Contains(out, []byte("does not exist"))) {
// surface the missing path and stop, rather than opaque downstream failures
return fmt.Errorf("go.mod replace target missing; fix go.mod: %s", out)
}
return err Prevention
- Keep local replace targets under the repo root and commit them.
- Pre-commit: stat each local replace path and fail fast.
- Avoid OS-specific absolute replace paths in shared go.mod files.
- Document required sibling checkouts in the project README.
When it happens
Trigger: go.mod contains 'replace example.com/foo => ./local/foo' and ./local/foo does not exist on the working directory / module root. Happens during package import resolution / build when that replacement is consulted.
Common situations: Checked out a fork branch without the local dir; relative replace path authored on a different OS layout; replace target was gitignored or not yet created; monorepo where the sibling module was not generated/built.
Related errors
- replacement directory %s: %w
- %s exists but is not a directory
- file is empty
- deleted in overlay
- cannot open directory in overlay
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/7748b8e4596db7a5.
Report an issue: GitHub.