{"record":{"id":"88aeaa6a2dcf2b20","repo":"golang/go","slug":"neither-gopath-nor-gomodcache-are-set","errorCode":null,"errorMessage":"neither GOPATH nor GOMODCACHE are set","messagePattern":"neither GOPATH nor GOMODCACHE are set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/modfetch/codehost/codehost.go","lineNumber":219,"sourceCode":"\t\treturn false\n\t}\n\treturn true\n}\n\n// ShortenSHA1 shortens a SHA1 hash (40 hex digits) to the canonical length\n// used in pseudo-versions (12 hex digits).\nfunc ShortenSHA1(rev string) string {\n\tif AllHex(rev) && len(rev) == 40 {\n\t\treturn rev[:12]\n\t}\n\treturn rev\n}\n\n// WorkDir returns the name of the cached work directory to use for the\n// given repository type and name.\nfunc WorkDir(ctx context.Context, typ, name string) (dir, lockfile string, err error) {\n\tif cfg.GOMODCACHE == \"\" {\n\t\treturn \"\", \"\", fmt.Errorf(\"neither GOPATH nor GOMODCACHE are set\")\n\t}\n\n\t// We name the work directory for the SHA256 hash of the type and name.\n\t// We intentionally avoid the actual name both because of possible\n\t// conflicts with valid file system paths and because we want to ensure\n\t// that one checkout is never nested inside another. That nesting has\n\t// led to security problems in the past.\n\tif strings.Contains(typ, \":\") {\n\t\treturn \"\", \"\", fmt.Errorf(\"codehost.WorkDir: type cannot contain colon\")\n\t}\n\tkey := typ + \":\" + name\n\tdir = filepath.Join(cfg.GOMODCACHE, \"cache/vcs\", fmt.Sprintf(\"%x\", sha256.Sum256([]byte(key))))\n\n\txLog, buildX := cfg.BuildXWriter(ctx)\n\tif buildX {\n\t\tfmt.Fprintf(xLog, \"mkdir -p %s # %s %s\\n\", filepath.Dir(dir), typ, name)\n\t}\n\tif err := os.MkdirAll(filepath.Dir(dir), 0777); err != nil {","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/modfetch/codehost/codehost.go#L201-L237","documentation":"Thrown by codehost.WorkDir when cfg.GOMODCACHE is empty, which only happens if neither GOPATH nor GOMODCACHE is set. WorkDir computes the VCS cache directory under GOMODCACHE/cache/vcs, so an empty cache root makes it impossible to place the work dir.","triggerScenarios":"Calling codehost.WorkDir (indirectly via go get/go mod download for a VCS-backed module) in an environment where both GOPATH and GOMODCACHE are unset — e.g. a stripped-down container, a misconfigured CI image, or GOFLAGS=-mod=mod with GOENV disabled.","commonSituations":"Minimal docker images that don't set GOPATH; CI environments that clear environment variables; GOPATH explicitly set to empty string.","solutions":["Set GOPATH: 'go env -w GOPATH=$HOME/go'.","Or set GOMODCACHE directly: 'go env -w GOMODCACHE=$HOME/go/pkg/mod'.","Verify with 'go env GOPATH GOMODCACHE' that both are non-empty.","In containers, add 'ENV GOPATH=/go' to the Dockerfile."],"exampleFix":"# before\ndocker run --rm -e GOPATH= golang go get example.com/mod\n# after\ndocker run --rm -e GOPATH=/go golang go get example.com/mod\n# or persistently\ngo env -w GOPATH=$HOME/go","handlingStrategy":"validation","validationCode":"func validateGoEnv() error {\n    gopath := os.Getenv(\"GOPATH\")\n    gomodcache := os.Getenv(\"GOMODCACHE\")\n    if gopath == \"\" && gomodcache == \"\" {\n        return fmt.Errorf(\"neither GOPATH nor GOMODCACHE is set\")\n    }\n    return nil\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Always set GOPATH in Dockerfiles: 'ENV GOPATH=/go'.","In CI, source a go env setup script before running builds.","Avoid unsetting environment variables in build scripts.","Add a pre-build assertion that GOPATH/GOMODCACHE are non-empty."],"tags":["config","gopath","gomodcache","environment"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}