The 2 AM Pipeline Failure
It’s 2 AM. You’re pushing a critical hotfix to production. The CI/CD pipeline starts, but instead of a green checkmark, you get a wall of red text. Or maybe you're just setting up a new hire's laptop. You run go mod tidy, and everything stalls. The terminal throws this at you:
go get github.com/acme-corp/secret-api: git ls-remote -q https://github.com/acme-corp/secret-api.git: exit status 128
This exit status 128 is Git’s generic way of saying "Access Denied." It happens because the Go toolchain is trying to reach a private repository as if it were a public one. The authentication handshake fails, and Git shuts down the connection.
Why Your Build is Breaking
By default, Go assumes every module is public. This creates two major roadblocks for private code:
- The Google Proxy: Go usually fetches modules from
proxy.golang.org. Since your repo is private, Google’s proxy can't see it. It returns a 404 or 410 error, and your build dies. - The HTTPS Trap: Go tries to fetch modules via HTTPS. If your machine uses SSH keys for GitHub but doesn't have a credential helper for HTTPS, Git will fail. It can't ask for your password in the middle of a non-interactive Go command.
Step 1: Define Your Private Space
Start by telling Go which modules should skip the public proxy and checksum database. Use the GOPRIVATE environment variable for this. It accepts comma-separated patterns.
Run this command in your terminal. Replace github.com/acme-corp with your actual organization:
go env -w GOPRIVATE=github.com/acme-corp/*
This simple flag does a lot. It tells Go that anything under the acme-corp path is private. Go will now bypass the Google proxy and the public checksum database (GOSUMDB) entirely for these repos.
Step 2: Force Git to Use SSH
Setting GOPRIVATE gets Go to talk to GitHub directly, but it still defaults to HTTPS. If you rely on SSH keys for development, you need to force Git to swap protocols on the fly.
Add this rewrite rule to your global .gitconfig:
git config --global url."git@github.com:".insteadOf "https://github.com/"
Now, when Go runs git ls-remote https://github.com/acme-corp/secret-api.git, Git intercepts it. It swaps the URL to git@github.com:acme-corp/secret-api.git. Your SSH agent handles the auth, and the download succeeds instantly.
CI/CD Alternative: Personal Access Tokens
In environments like GitHub Actions or Jenkins, managing SSH keys is often a hassle. Using a Personal Access Token (PAT) via HTTPS is usually cleaner.
Instead of the SSH rewrite, use this command in your CI script:
# For GitHub Actions
git config --global url."https://${GH_TOKEN}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
Security Tip: Never hardcode this token. Use environment variables or secrets management to inject the ${GH_TOKEN} at runtime to keep your credentials safe.
Step 3: Verify the Fix
Clear your local module cache to ensure you aren't looking at old, broken metadata. Then, try to resolve the dependencies again.
go clean -modcache
go mod tidy
If the command finishes silently, you've won. You can double-check your settings anytime by running go env GOPRIVATE.
Common Pitfalls to Watch For
1. The Colon vs. Slash Trap
When using insteadOf, the syntax is picky. If you use git@github.com: (with a colon), ensure the HTTPS side matches with https://github.com/ (with a trailing slash). A tiny mismatch here results in broken URLs like git@github.com:/user/repo, which will trigger another 128 error.
2. The Checksum Database
Some developers try to use GONOPROXY alone. Don't do this. If you skip the proxy but not the checksum database (GOSUMDB), Go will still try to verify your private code against a public ledger. It will fail because your private code isn't in that ledger. GOPRIVATE is the safer bet because it configures both settings at once.
3. Docker Container Issues
Docker builds are a frequent source of 128 errors. The container is a clean slate; it doesn't know about your host's .gitconfig or SSH keys. You must explicitly set the environment variables inside your Dockerfile or pass them as build arguments.
# Example Dockerfile snippet
ARG GITHUB_TOKEN
ENV GOPRIVATE=github.com/acme-corp/*
RUN git config --global url."https://${GITHUB_TOKEN}:x-oauth-basic@github.com/".insteadOf "https://github.com/"
Summary
- Go's default setup assumes all code is public. For internal projects,
GOPRIVATEis your best friend. - An
exit status 128almost always boils down to a Git authentication failure. - The
insteadOftrick is the cleanest way to fix protocol mismatches without touching yourgo.modfile.

