golang/go · error

missing top-level directory prefix

Error message

missing top-level directory prefix

What it means

While re-wrapping a downloaded archive into the module-zip layout, codeRepo.Zip scans entries and requires every entry to live under exactly one top-level directory. If the first scanned entry contains no '/' separator it sits at the archive root, so no top-level prefix can be established, and the archive is rejected as malformed.

Source

Thrown at src/cmd/go/internal/modfetch/coderepo.go:1147

	}

	// Translate from zip file we have to zip file we want.
	zr, err := zip.NewReader(f, size)
	if err != nil {
		return err
	}

	var files []modzip.File
	if subdir != "" {
		subdir += "/"
	}
	haveLICENSE := false
	topPrefix := ""
	for _, zf := range zr.File {
		if topPrefix == "" {
			i := strings.Index(zf.Name, "/")
			if i < 0 {
				return fmt.Errorf("missing top-level directory prefix")
			}
			topPrefix = zf.Name[:i+1]
		}
		var name string
		var found bool
		if name, found = strings.CutPrefix(zf.Name, topPrefix); !found {
			return fmt.Errorf("zip file contains more than one top-level directory")
		}

		if name, found = strings.CutPrefix(name, subdir); !found {
			continue
		}

		if name == "" || strings.HasSuffix(name, "/") {
			continue
		}
		files = append(files, zipFile{name: name, f: zf})
		if name == "LICENSE" {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Clear the module cache for the affected module: go clean -modcache (or remove the specific cache dir) and re-download from a trusted proxy.
  2. Switch GOPROXY to a conformant source such as https://proxy.golang.org,direct.
  3. If you operate the proxy, ensure produced archives contain a single top-level directory with every file under it.
Defensive patterns

Strategy: validation

Validate before calling

// Verify a module archive has a single top-level directory before serving
// it from your own proxy.
func zipHasTopPrefix(p string) error {
    r, err := zip.OpenReader(p)
    if err != nil { return err }
    defer r.Close()
    for _, zf := range r.File {
        if !strings.Contains(zf.Name, "/") {
            return fmt.Errorf("entry %q has no top-level dir", zf.Name)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A module proxy or origin returns a zip whose first entry is a bare filename with no directory (e.g. "README" instead of "modroot@v1.0.0/README"). The strings.Index returns -1 and the error fires.

Common situations: A custom GOPROXY that zips content incorrectly; a manually constructed or corrupted cache file; an upstream VCS export that flattens the tree.

Related errors


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