golang/go · error

%s@%s used for two different module paths (%s and %s)

Error message

%s@%s used for two different module paths (%s and %s)

What it means

Thrown by checkMultiplePathsUncached (load.go:2044) when the same module source (resolveReplacement(mod) — which resolves to the module itself or its replacement) is referenced by two different module paths. The map firstPath[src] tracks the first path seen for each source; if a later module shares the source but has a different Path, the conflict is reported. This indicates a module graph where one physical source is ambiguously attributed to two logical modules.

Source

Thrown at src/cmd/go/internal/modload/load.go:2044

			// directives, both fixed for the lifetime of mg, so skip it on
			// subsequent calls sharing the same graph.
			mg.checkPathsOnce.Do(func() {
				checkMultiplePathsUncached(ld, pld, mg.BuildList())
			})
			return
		}
	}
	checkMultiplePathsUncached(ld, pld, pld.requirements.rootModules)
}

func checkMultiplePathsUncached(ld *Loader, pld *packageLoader, mods []module.Version) {
	firstPath := map[module.Version]string{}
	for _, mod := range mods {
		src := resolveReplacement(ld, mod)
		if prev, ok := firstPath[src]; !ok {
			firstPath[src] = mod.Path
		} else if prev != mod.Path {
			pld.error(fmt.Errorf("%s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path))
		}
	}
}

// checkTidyCompatibility emits an error if any package would be loaded from a
// different module under rs than under ld.requirements.
func (pld *packageLoader) checkTidyCompatibility(ld *Loader, ctx context.Context, rs *Requirements, compatVersion string) {
	goVersion := rs.GoVersion(ld)
	suggestUpgrade := false
	suggestEFlag := false
	suggestFixes := func() {
		if pld.AllowErrors {
			// The user is explicitly ignoring these errors, so don't bother them with
			// other options.
			return
		}

		// We print directly to os.Stderr because this information is advice about

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Inspect go.mod and go.work 'replace' directives for two different module paths pointing at the same source.
  2. Ensure each module path maps to a distinct source directory or version.
  3. If using a local replacement, give each replaced module its own directory.

Example fix

// before (go.mod)
replace (
    example.com/a => ./local
    example.com/b => ./local
)

// after — distinct sources per module path
replace (
    example.com/a => ./local-a
    example.com/b => ./local-b
)
Defensive patterns

Strategy: validation

Validate before calling

// Detect replace directives that alias distinct module paths to the same source.
func checkDuplicateReplaces(replacements []Replace) error {
    seen := map[string]string{} // source -> first path
    for _, r := range replacements {
        src := r.New.Path + "@" + r.New.Version
        if r.New.Version == "" {
            src = r.New.Path // local replacement
        }
        if prev, ok := seen[src]; ok && prev != r.Old.Path {
            return fmt.Errorf("%s used for two module paths (%s and %s)", src, prev, r.Old.Path)
        }
        seen[src] = r.Old.Path
    }
    return nil
}

Prevention

When it happens

Trigger: Two different module paths in the build list resolve (possibly via 'replace' directives) to the same filesystem source or the same module@version. For example, replace directives pointing distinct module paths at the same local directory, or a replacement that aliases module paths.

Common situations: Multiple 'replace' directives in go.mod pointing different module paths at the same local directory. A forked module published under a new path but accidentally sharing a version string with the original. Complex workspace setups with overlapping replacements.

Related errors


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