The Error
go: could not create module cache: mkdir /go/pkg/mod: permission denied
Go can't write to its module cache directory. This usually surfaces when building inside Docker containers, running jobs in CI/CD pipelines, or after someone ran a go command with sudo โ which stamps the cache with root ownership and locks out your normal user.
Why This Happens
Go caches downloaded modules at $GOPATH/pkg/mod. Inside Docker images that's usually /go/pkg/mod; on a regular Linux or macOS machine it defaults to ~/go/pkg/mod.
The most common causes:
- Docker image ran a previous step as root, creating
/go/pkg/modwith root ownership before your app user runsgo build. - Someone ran
sudo go getorsudo go buildon a shared machine, which seeded the cache as root. - GOPATH is set to a system directory (
/go,/usr/local/go) that your current user can't write to. - CI/CD runner mounts a volume or cache that was created by a different user in a previous job.
Fix 1 โ Change Ownership of the Cache Directory (Most Common)
The cache got taken over by root. Take it back:
# Check who owns it
ls -la $(go env GOPATH)/pkg/mod
# Fix ownership (replace $USER with your username if needed)
sudo chown -R $USER:$USER $(go env GOPATH)/pkg/mod
Retry your go build or go mod download โ it should work immediately.
Fix 2 โ Point GOMODCACHE to a Writable Directory
On shared servers or restricted environments where you can't chown anything, redirect the cache to somewhere you already own:
# Temporary (current session only)
export GOMODCACHE=$HOME/go/pkg/mod
# Permanent โ add to ~/.bashrc or ~/.zshrc
echo 'export GOMODCACHE=$HOME/go/pkg/mod' >> ~/.bashrc
source ~/.bashrc
# Verify
go env GOMODCACHE
Run go mod download after setting this. Go will create the new cache path under your home directory and use it from then on.
Fix 3 โ Fix GOPATH (If Pointing to a System Directory)
Check what GOPATH currently resolves to:
go env GOPATH
Output like /go or /usr/local/go is the culprit โ those paths are owned by root. Reset to a user-owned location:
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
# Add to shell profile for persistence
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc
Fix 4 โ Docker Container Fix
Docker is where this error bites most often. A layer runs go commands as root, stamping /go/pkg/mod with root ownership. Then a later step switches to a non-root user โ and that user can't touch the cache.
Option A โ Run everything as the same user:
FROM golang:1.22
# All go commands run as root โ consistent, no permission mismatch
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o myapp .
Option B โ Create a non-root user and set GOPATH under their home:
FROM golang:1.22
RUN useradd -m -u 1001 appuser
USER appuser
WORKDIR /home/appuser/app
# GOPATH defaults to ~/go, which appuser owns
COPY --chown=appuser:appuser go.mod go.sum ./
RUN go mod download
COPY --chown=appuser:appuser . .
RUN go build -o myapp .
Option C โ Explicitly set GOMODCACHE to a writable path in Dockerfile:
ENV GOMODCACHE=/tmp/gomodcache
RUN go mod download
Fix 5 โ CI/CD Pipeline (GitHub Actions / GitLab CI)
Caching Go modules between pipeline runs speeds things up โ but a stale cache volume owned by the wrong user breaks everything. The safest approach: let the official setup action handle GOMODCACHE, and don't override GOPATH manually.
# GitHub Actions example
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
# The setup-go action sets GOMODCACHE correctly โ don't override GOPATH manually
- name: Download modules
run: go mod download
Running a self-hosted runner? A previous job may have left a root-owned cache behind. Clear it and start fresh:
sudo rm -rf ~/go/pkg/mod
go mod download
Verify the Fix
Run these after applying any fix above:
# Check cache directory exists and is accessible
ls -la $(go env GOMODCACHE)
# Try downloading modules fresh
go mod download
# Or just build your project
go build ./...
No permission errors and a clean build output means you're done.
Prevention Tips
- Never use
sudo go ...โ if agocommand needs elevated access, something in your setup is wrong. Fix the underlying permission issue instead. - In Docker: decide on root vs. non-root early in your Dockerfile design and stay consistent throughout all layers that run
gocommands. - Set GOPATH explicitly in your shell profile rather than relying on the default, especially on servers where multiple users share the same Go installation.
- Check directory permissions visually: if you're unsure whether your
chmodandchowncommands produce the right result, the Unix Permissions Calculator on ToolCraft lets you build and verify permission strings in the browser โ useful when you're dealing with multi-user Docker setups and want to double-check the numbers before applying them.

