golang/go · error

malformed module path %q

Error message

malformed module path %q

What it means

fixVersion (the modfile.VersionFixer used when reading go.mod) was called on a (path, version) pair and module.SplitPathVersion(path) returned !ok, meaning the path itself is structurally malformed. Returned as module.ModuleError wrapping module.InvalidVersionError. This is a speculative fixer so it bails fast on obviously-bad paths.

Source

Thrown at src/cmd/go/internal/modload/init.go:1306

				*fixed = true
			}
		}()

		// Special case: remove the old -gopkgin- hack.
		if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") {
			vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):]
		}

		// fixVersion is called speculatively on every
		// module, version pair from every go.mod file.
		// Avoid the query if it looks OK.
		_, pathMajor, ok := module.SplitPathVersion(path)
		if !ok {
			return "", &module.ModuleError{
				Path: path,
				Err: &module.InvalidVersionError{
					Version: vers,
					Err:     fmt.Errorf("malformed module path %q", path),
				},
			}
		}
		if vers != "" && module.CanonicalVersion(vers) == vers {
			if err := module.CheckPathMajor(vers, pathMajor); err != nil {
				return "", module.VersionError(module.Version{Path: path, Version: vers}, err)
			}
			return vers, nil
		}

		info, err := Query(ld, ctx, path, vers, "", nil)
		if err != nil {
			return "", err
		}
		return info.Version, nil
	}
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Inspect go.mod for the offending module path and correct it to a valid domain/path form.
  2. If the entry is stale, remove the require/replace/exclude line.
  3. Run 'go mod tidy' / 'go mod edit' to rewrite the file once the path is valid.
  4. Ensure no control characters or smart-quotes were introduced by copy-paste.

Example fix

// before (go.mod)
require example.com/foo@bad path v1.2.3   // path has a space / bad token
// fixVersion: malformed module path "example.com/foo@bad path"

// after
require example.com/foo v1.2.3
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate every module path in go.mod via SplitPathVersion.
data, err := os.ReadFile("go.mod")
if err != nil { return err }
f, _ := modfile.Parse("go.mod", data, nil)
check := func(path string) error {
    if _, _, ok := module.SplitPathVersion(path); !ok {
        return fmt.Errorf("malformed module path %q", path)
    }
    return nil
}
for _, r := range f.Require { if e := check(r.Mod.Path); e != nil { return e } }
for _, r := range f.Replace { if e := check(r.New.Path); e != nil { return e } }

Type guard

func isWellFormedModulePath(p string) bool {
    _, _, ok := module.SplitPathVersion(p); return ok
}

Try / catch

out, err := exec.Command("go", "build", "./...").CombinedOutput()
if err != nil && bytes.Contains(out, []byte("malformed module path")) {
    // surface the offending path from go.mod; do not retry until edited
    return fmt.Errorf("go.mod has a malformed module path; fix require/replace entries: %s", out)
}
return err

Prevention

When it happens

Trigger: A require/replace/exclude entry in go.mod references a module whose path SplitPathVersion cannot parse (no domain, illegal characters, malformed version token glued to path). fixVersion returns this ModuleError instead of attempting a Query.

Common situations: Hand-edited go.mod with a typo in a require path; a generated/templated go.mod with a bad substitution; a replace target path that violates module path grammar; mixed encoding issues.

Understand the failure class

Related errors


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