Files
Charon/docs/development/go_version_upgrades.md
GitHub Actions ca477c48d4 chore: Enhance documentation for E2E testing:
- Added clarity and structure to README files, including recent updates and getting started sections.
- Improved manual verification documentation for CrowdSec authentication, emphasizing expected outputs and success criteria.
- Updated debugging guide with detailed output examples and automatic trace capture information.
- Refined best practices for E2E tests, focusing on efficient polling, locator strategies, and state management.
- Documented triage report for DNS Provider feature tests, highlighting issues fixed and test results before and after improvements.
- Revised E2E test writing guide to include when to use specific helper functions and patterns for better test reliability.
- Enhanced troubleshooting documentation with clear resolutions for common issues, including timeout and token configuration problems.
- Updated tests README to provide quick links and best practices for writing robust tests.
2026-03-24 01:47:22 +00:00

10 KiB

Go Version Upgrades

Last Updated: 2026-02-12

The Short Version

When Charon upgrades to a new Go version, your development tools (like golangci-lint) break. Here's how to fix it:

# Step 1: Pull latest code
git pull

# Step 2: Update your Go installation
.github/skills/scripts/skill-runner.sh utility-update-go-version

# Step 3: Rebuild tools
./scripts/rebuild-go-tools.sh

# Step 4: Restart your IDE
# VS Code: Cmd/Ctrl+Shift+P → "Developer: Reload Window"

That's it! Keep reading if you want to understand why.


What's Actually Happening?

The Problem (In Plain English)

Think of Go tools like a Swiss Army knife. When you upgrade Go, it's like switching from metric to imperial measurements—your old knife still works, but the measurements don't match anymore.

Here's what breaks:

  1. Renovate updates the project to Go 1.26.0
  2. Your tools are still using Go 1.25.6
  3. Pre-commit hooks fail with confusing errors
  4. Your IDE gets confused and shows red squiggles everywhere

Why Tools Break

Development tools like golangci-lint are compiled programs. They were built with Go 1.25.6 and expect Go 1.25.6's features. When you upgrade to Go 1.26.0:

  • New language features exist that old tools don't understand
  • Standard library functions change
  • Your tools throw errors like: undefined: someNewFunction

The Fix: Rebuild tools with the new Go version so they match your project.


Step-by-Step Upgrade Guide

Step 1: Know When an Upgrade Happened

Renovate (our automated dependency manager) will open a PR titled something like:

chore(deps): update golang to v1.26.0

When this gets merged, you'll need to update your local environment.

Step 2: Pull the Latest Code

cd /projects/Charon
git checkout development
git pull origin development

Step 3: Update Your Go Installation

Option A: Use the Automated Skill (Recommended)

.github/skills/scripts/skill-runner.sh utility-update-go-version

This script:

  • Detects the required Go version from go.work
  • Downloads it from golang.org
  • Installs it to ~/sdk/go{version}/
  • Updates your system symlink to point to it
  • Rebuilds your tools automatically

Option B: Manual Installation

If you prefer to install Go manually:

  1. Go to go.dev/dl
  2. Download the version mentioned in the PR (e.g., 1.26.0)
  3. Install it following the official instructions
  4. Verify: go version should show the new version
  5. Continue to Step 4

Step 4: Rebuild Development Tools

Even if you used Option A (which rebuilds automatically), you can always manually rebuild:

./scripts/rebuild-go-tools.sh

This rebuilds:

  • golangci-lint — Pre-commit linter (critical)
  • gopls — IDE language server (critical)
  • govulncheck — Security scanner
  • dlv — Debugger

Duration: About 30 seconds

Output: You'll see:

🔧 Rebuilding Go development tools...
Current Go version: go version go1.26.0 linux/amd64

📦 Installing golangci-lint...
✅ golangci-lint installed successfully

📦 Installing gopls...
✅ gopls installed successfully

...

✅ All tools rebuilt successfully!

Step 5: Restart Your IDE

Your IDE caches the old Go language server (gopls). Reload to use the new one:

VS Code:

  • Press Cmd/Ctrl+Shift+P
  • Type "Developer: Reload Window"
  • Press Enter

GoLand or IntelliJ IDEA:

  • File → Invalidate Caches → Restart
  • Wait for indexing to complete

Step 6: Verify Everything Works

Run a quick test:

# This should pass without errors
go test ./backend/...

If tests pass, you're done! 🎉


Troubleshooting

Error: "golangci-lint: command not found"

Problem: Your $PATH doesn't include Go's binary directory.

Fix:

# Add to ~/.bashrc or ~/.zshrc
export PATH="$PATH:$(go env GOPATH)/bin"

# Reload your shell
source ~/.bashrc  # or source ~/.zshrc

Then rebuild tools:

./scripts/rebuild-go-tools.sh

Error: Pre-commit hook still failing

Problem: Pre-commit is using a cached version of the tool.

Fix 1: Let the hook auto-rebuild

The pre-commit hook detects version mismatches and rebuilds automatically. Just commit again:

git commit -m "your message"
# Hook detects mismatch, rebuilds tool, and retries

Fix 2: Manual rebuild

./scripts/rebuild-go-tools.sh
git commit -m "your message"

Error: "package X is not in GOROOT"

Problem: Your project's go.work or go.mod specifies a Go version you don't have installed.

Check required version:

grep '^go ' go.work
# Output: go 1.26.0

Install that version:

.github/skills/scripts/skill-runner.sh utility-update-go-version

IDE showing errors but code compiles fine

Problem: Your IDE's language server (gopls) is out of date.

Fix:

# Rebuild gopls
go install golang.org/x/tools/gopls@latest

# Restart IDE
# VS Code: Cmd/Ctrl+Shift+P → "Developer: Reload Window"

"undefined: someFunction" errors

Problem: Your tools were built with an old Go version and don't recognize new standard library functions.

Fix:

./scripts/rebuild-go-tools.sh

Frequently Asked Questions

How often do Go versions change?

Go releases two major versions per year:

  • February (e.g., Go 1.26.0)
  • August (e.g., Go 1.27.0)

Plus occasional patch releases (e.g., Go 1.26.1) for security fixes.

Bottom line: Expect to run ./scripts/rebuild-go-tools.sh 2-3 times per year.

Do I need to rebuild tools for patch releases?

Usually no, but it doesn't hurt. Patch releases (like 1.26.0 → 1.26.1) rarely break tool compatibility.

Rebuild if:

  • Pre-commit hooks start failing
  • IDE shows unexpected errors
  • Tools report version mismatches

Why don't CI builds have this problem?

CI environments are ephemeral (temporary). Every workflow run:

  1. Starts with a fresh container
  2. Installs Go from scratch
  3. Installs tools from scratch
  4. Runs tests
  5. Throws everything away

Local development has persistent tool installations that get out of sync.

Can I use multiple Go versions on my machine?

Yes! Go officially supports this via golang.org/dl:

# Install Go 1.25.6
go install golang.org/dl/go1.25.6@latest
go1.25.6 download

# Install Go 1.26.0
go install golang.org/dl/go1.26.0@latest
go1.26.0 download

# Use specific version
go1.25.6 version
go1.26.0 test ./...

But for Charon development, you only need one version (whatever's in go.work).

What if I skip an upgrade?

Short answer: Your local tools will be out of sync, but CI will still work.

What breaks:

  • Pre-commit hooks fail (but will auto-rebuild)
  • IDE shows phantom errors
  • Manual go test might fail locally
  • CI is unaffected (it always uses the correct version)

When to catch up:

  • Before opening a PR (CI checks will fail if your code uses old Go features)
  • When local development becomes annoying

Should I keep old Go versions installed?

No need. The upgrade script preserves old versions in ~/sdk/, but you don't need to do anything special.

If you want to clean up:

# See installed versions
ls ~/sdk/

# Remove old versions
rm -rf ~/sdk/go1.25.5
rm -rf ~/sdk/go1.25.6

But they only take ~400MB each, so cleanup is optional.

Why doesn't Renovate upgrade tools automatically?

Renovate updates Dockerfile and go.work, but it can't update tools on your machine.

Think of it like this:

  • Renovate: "Hey team, we're now using Go 1.26.0"
  • Your machine: "Cool, but my tools are still Go 1.25.6. Let me rebuild them."

The rebuild script bridges that gap.

What's the difference between go.work, go.mod, and my system Go?

go.work — Workspace file (multi-module projects like Charon)

  • Specifies minimum Go version for the entire project
  • Used by Renovate to track upgrades

go.mod — Module file (individual Go modules)

  • Each module (backend, tools) has its own go.mod
  • Inherits Go version from go.work

System Go (go version) — What's installed on your machine

  • Must be >= the version in go.work
  • Tools are compiled with whatever version this is

Example:

go.work says: "Use Go 1.26.0 or newer"
go.mod says: "I'm part of the workspace, use its Go version"
Your machine: "I have Go 1.26.0 installed"
Tools: "I was built with Go 1.25.6" ❌ MISMATCH

Running ./scripts/rebuild-go-tools.sh fixes the mismatch.


Advanced: Pre-commit Auto-Rebuild

Charon's pre-commit hook automatically detects and fixes tool version mismatches.

How it works:

  1. Check versions:

    golangci-lint version → "built with go1.25.6"
    go version → "go version go1.26.0"
    
  2. Detect mismatch:

    ⚠️  golangci-lint Go version mismatch:
       golangci-lint: 1.25.6
       system Go:     1.26.0
    
  3. Auto-rebuild:

    🔧 Rebuilding golangci-lint with current Go version...
    ✅ golangci-lint rebuilt successfully
    
  4. Retry linting: Hook runs again with the rebuilt tool.

What this means for you:

The first commit after a Go upgrade will be slightly slower (~30 seconds for tool rebuild). Subsequent commits are normal speed.

Disabling auto-rebuild:

If you want manual control, edit scripts/pre-commit-hooks/golangci-lint-fast.sh and remove the rebuild logic. (Not recommended.)



Need Help?

Open a Discussion if:

  • These instructions didn't work for you
  • You're seeing errors not covered in troubleshooting
  • You have suggestions for improving this guide

Open an Issue if:

  • The rebuild script crashes
  • Pre-commit auto-rebuild isn't working
  • CI is failing for Go version reasons

Remember: Go upgrades happen 2-3 times per year. When they do, just run ./scripts/rebuild-go-tools.sh and you're good to go! 🚀