{"record":{"id":"ec2ce78f9e5ae234","repo":"golang/go","slug":"missing-top-level-directory-prefix","errorCode":null,"errorMessage":"missing top-level directory prefix","messagePattern":"missing top-level directory prefix","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/coderepo.go","lineNumber":1147,"sourceCode":"\t}\n\n\t// Translate from zip file we have to zip file we want.\n\tzr, err := zip.NewReader(f, size)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar files []modzip.File\n\tif subdir != \"\" {\n\t\tsubdir += \"/\"\n\t}\n\thaveLICENSE := false\n\ttopPrefix := \"\"\n\tfor _, zf := range zr.File {\n\t\tif topPrefix == \"\" {\n\t\t\ti := strings.Index(zf.Name, \"/\")\n\t\t\tif i < 0 {\n\t\t\t\treturn fmt.Errorf(\"missing top-level directory prefix\")\n\t\t\t}\n\t\t\ttopPrefix = zf.Name[:i+1]\n\t\t}\n\t\tvar name string\n\t\tvar found bool\n\t\tif name, found = strings.CutPrefix(zf.Name, topPrefix); !found {\n\t\t\treturn fmt.Errorf(\"zip file contains more than one top-level directory\")\n\t\t}\n\n\t\tif name, found = strings.CutPrefix(name, subdir); !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tif name == \"\" || strings.HasSuffix(name, \"/\") {\n\t\t\tcontinue\n\t\t}\n\t\tfiles = append(files, zipFile{name: name, f: zf})\n\t\tif name == \"LICENSE\" {","sourceCodeStart":1129,"sourceCodeEnd":1165,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/coderepo.go#L1129-L1165","documentation":"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.","triggerScenarios":"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.","commonSituations":"A custom GOPROXY that zips content incorrectly; a manually constructed or corrupted cache file; an upstream VCS export that flattens the tree.","solutions":["Clear the module cache for the affected module: go clean -modcache (or remove the specific cache dir) and re-download from a trusted proxy.","Switch GOPROXY to a conformant source such as https://proxy.golang.org,direct.","If you operate the proxy, ensure produced archives contain a single top-level directory with every file under it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify a module archive has a single top-level directory before serving\n// it from your own proxy.\nfunc zipHasTopPrefix(p string) error {\n    r, err := zip.OpenReader(p)\n    if err != nil { return err }\n    defer r.Close()\n    for _, zf := range r.File {\n        if !strings.Contains(zf.Name, \"/\") {\n            return fmt.Errorf(\"entry %q has no top-level dir\", zf.Name)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only trust proxies known to emit well-formed archives.","Treat a 1004/1005 as cache corruption first and clean before deeper debugging."],"tags":["zip","archive","structure","proxy"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}