golang/go · error
zip file contains more than one top-level directory
Error message
zip file contains more than one top-level directory
What it means
Companion to 1004. Once the top-level prefix is locked in from the first entry, every subsequent entry must start with that prefix. Finding an entry that does not means the archive contains more than one top-level directory, which would let a module smuggle files outside its namespace.
Source
Thrown at src/cmd/go/internal/modfetch/coderepo.go:1154
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" {
haveLICENSE = true
}
}
if !haveLICENSE && subdir != "" {
data, err := r.code.ReadFile(ctx, rev, "LICENSE", codehost.MaxLICENSE)
if err == nil {View on GitHub (pinned to b6b368adc5)
Solutions
- Purge the suspect cache entry and re-download.
- Point GOPROXY at a compliant proxy (https://proxy.golang.org,direct) that always emits a single top-level dir.
- If self-hosting the proxy, validate that the upstream archive contains exactly one root directory before serving.
Defensive patterns
Strategy: validation
Validate before calling
func zipSingleTopDir(p string) error {
r, err := zip.OpenReader(p)
if err != nil { return err }
defer r.Close()
top := ""
for _, zf := range r.File {
i := strings.Index(zf.Name, "/")
if i < 0 { return fmt.Errorf("no top dir") }
if top == "" { top = zf.Name[:i+1] }
if !strings.HasPrefix(zf.Name, top) {
return fmt.Errorf("multiple top dirs: %q vs %q", top, zf.Name)
}
}
return nil
} Prevention
- Validate served archives with the single-top-dir invariant.
- Periodically verify your modcache with `go mod verify`.
When it happens
Trigger: strings.CutPrefix(zf.Name, topPrefix) returns found=false for some entry — e.g. archive holds both projectA/... and projectB/... at the top level.
Common situations: Multi-project repos packaged into one zip by a misbehaving proxy; corrupted download; cache tampering.
Related errors
- missing top-level directory prefix
- invalid file name: %v
- decompressor already registered
- compressor already registered
- zip: SetOffset called after data was written
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/aa7ce7d0cbb01982.
Report an issue: GitHub.