- Update import paths to github.com/oschwald/geoip2-golang/v2 - Handle API breaking changes (net.IP → netip.Addr, IsoCode → ISOCode) - Fix VERSION.md to match git tag (0.7.13) - Resolves CI failure in benchmark workflow
11 KiB
CI/CD Failure Diagnosis Report
Date: December 14, 2025
GitHub Actions Run: #20204673793
Workflow: benchmark.yml (Go Benchmark)
Status: ❌ Failed
Commit: 8489394 - Merge pull request #396
Executive Summary
The CI/CD failure is caused by an incomplete Go module migration from github.com/oschwald/geoip2-golang v1 to v2. The Renovate bot PR #396 updated go.mod to use v2 of the package, but:
- The actual source code still imports the v1 package path (without
/v2) - This created a mismatch where
go.moddeclares v2 but the code imports v1 - The module resolution system cannot find the v1 package because it's been removed from
go.mod
Root Cause: Import path incompatibility between major versions in Go modules. When upgrading from v1 to v2 of a Go module, both the go.mod AND the import statements in source files must be updated to include the /v2 suffix.
Workflow Description
What the Failing Workflow Does
The benchmark.yml workflow (Go Benchmark) performs:
- Checkout repository code
- Set up Go environment (v1.25.5)
- Run benchmarks on backend code using
go test -bench=. - Store benchmark results (only on pushes to main branch)
- Run performance assertions to catch regressions
Purpose: Continuous performance monitoring to detect regressions before they reach production.
Trigger: Runs on push/PR to main or development branches when backend files change.
Failing Step Details
Step: "Performance Regression Check"
Error Messages (9 identical errors):
no required module provides package github.com/oschwald/geoip2-golang; to add it:
go get github.com/oschwald/geoip2-golang
Exit Code: 1 (compilation failure)
Phase: Build/compilation phase during go test execution
Affected Files:
/projects/Charon/backend/internal/services/geoip_service.go(line 9)/projects/Charon/backend/internal/services/geoip_service_test.go(line 10)
Renovate Changes Analysis
PR #396: Update github.com/oschwald/geoip2-golang to v2
Branch: renovate/github.com-oschwald-geoip2-golang-2.x
Merge Commit: 8489394 into development
Changes Made by Renovate:
# backend/go.mod
- github.com/oschwald/geoip2-golang v1.13.0
+ github.com/oschwald/geoip2-golang/v2 v2.0.1
Issue: Renovate added the v2 dependency but also left a duplicate entry, resulting in:
require (
// ... other deps ...
github.com/oschwald/geoip2-golang/v2 v2.0.1 // ← ADDED BY RENOVATE
github.com/oschwald/geoip2-golang/v2 v2.0.1 // ← DUPLICATE!
// ... other deps ...
)
The v1 dependency was removed from go.mod.
Related Commits:
8489394: Merge PR #396dd9a559: Renovate branch with geoip2 v2 update6469c6a: Previous development state (had v1)
Root Cause Analysis
The Problem
Go modules use semantic import versioning. For major version 2 and above, the import path must include the major version:
v1 (or unversioned):
import "github.com/oschwald/geoip2-golang"
v2+:
import "github.com/oschwald/geoip2-golang/v2"
What Happened
-
Before PR #396:
go.mod: containedgithub.com/oschwald/geoip2-golang v1.13.0- Source code: imports
github.com/oschwald/geoip2-golang - ✅ Everything aligned and working
-
After PR #396 (Renovate):
go.mod: containsgithub.com/oschwald/geoip2-golang/v2 v2.0.1(duplicate entry)- Source code: still imports
github.com/oschwald/geoip2-golang(v1 path) - ❌ Mismatch: code wants v1, but only v2 is available
-
Go Module Resolution:
- When Go sees
import "github.com/oschwald/geoip2-golang", it looks for a module matching that path go.modonly hasgithub.com/oschwald/geoip2-golang/v2- These are different module paths in Go's eyes
- Result: "no required module provides package"
- When Go sees
Verification
Running go mod tidy shows:
go: finding module for package github.com/oschwald/geoip2-golang
go: found github.com/oschwald/geoip2-golang in github.com/oschwald/geoip2-golang v1.13.0
unused github.com/oschwald/geoip2-golang/v2
This confirms:
- Go finds v1 when analyzing imports
- v2 is declared but unused
- The imports and go.mod are out of sync
Impact Assessment
Directly Affected
-
✅ security-weekly-rebuild.yml (the file currently open in editor): NOT affected
- This workflow builds Docker images and doesn't run Go tests directly
- It will succeed if the Docker build process works
-
❌ benchmark.yml: FAILING
- Cannot compile backend code
- Blocks performance regression checks
Potentially Affected
All workflows that compile or test backend Go code:
go-build.ymlor similar build workflowsgo-test.ymlor test workflows- Any integration tests that compile the backend
- Docker builds that include
go buildsteps inside the container
Why Renovate Didn't Handle This
Renovate's Behavior:
- Renovate excels at updating dependency declarations (in
go.mod,package.json, etc.) - It updates version numbers and dependency paths in configuration files
- However, it does not modify source code imports automatically
Why Import Updates Are Manual:
- Import path changes are code changes, not config changes
- Requires semantic understanding of the codebase
- May involve API changes that need human review
- Risk of breaking changes in major version bumps
Expected Workflow for Major Go Module Updates:
- Renovate creates PR updating
go.modwith v2 path - Human reviewer identifies this requires import changes
- Developer manually updates all import statements
- Tests confirm everything works with v2 API
- PR is merged
What Went Wrong:
- Renovate was configured for automerge on patch updates
- This appears to have been a major version update (v1 → v2)
- Either automerge rules were too permissive, or manual review was skipped
- The duplicate entry in
go.modsuggests a merge conflict or incomplete update
Recommended Fix Approach
Step 1: Update Import Statements
Replace all occurrences of v1 import path with v2:
Files to Update:
backend/internal/services/geoip_service.go(line 9)backend/internal/services/geoip_service_test.go(line 10)
Change:
// FROM:
import "github.com/oschwald/geoip2-golang"
// TO:
import "github.com/oschwald/geoip2-golang/v2"
Step 2: Remove Duplicate go.mod Entry
File: backend/go.mod
Issue: Line 13 and 14 both have:
github.com/oschwald/geoip2-golang/v2 v2.0.1
github.com/oschwald/geoip2-golang/v2 v2.0.1 // ← DUPLICATE
Fix: Remove one duplicate entry.
Step 3: Run go mod tidy
cd backend
go mod tidy
This will:
- Clean up any unused dependencies
- Update
go.sumwith correct checksums for v2 - Verify all imports are satisfied
Step 4: Verify the Build
cd backend
go build ./...
go test ./...
Step 5: Check for API Changes
IMPORTANT: Major version bumps may include breaking API changes.
Review the geoip2-golang v2.0.0 release notes for:
- Renamed functions or types
- Changed function signatures
- Deprecated features
Update code accordingly if the API has changed.
Step 6: Test Affected Workflows
Trigger the benchmark workflow to confirm it passes:
git push origin development
Prevention Recommendations
1. Update Renovate Configuration
Add a rule to prevent automerge on major version updates for Go modules:
{
"packageRules": [
{
"description": "Manual review required for Go major version updates",
"matchManagers": ["gomod"],
"matchUpdateTypes": ["major"],
"automerge": false,
"labels": ["dependencies", "go", "manual-review", "breaking-change"]
}
]
}
This ensures major updates wait for human review to handle import path changes.
2. Add Pre-merge CI Check
Ensure the benchmark workflow (or a build workflow) runs on PRs to development:
# benchmark.yml already has this
pull_request:
branches:
- main
- development
This would have caught the issue before merge.
3. Document Major Update Process
Create a checklist for major Go module updates:
- Update
go.modversion - Update import paths in all source files (add
/v2,/v3, etc.) - Run
go mod tidy - Review release notes for breaking changes
- Update code for API changes
- Run full test suite
- Verify benchmarks pass
4. Go Module Update Script
Create a helper script to automate import path updates:
# scripts/update-go-major-version.sh
# Usage: ./scripts/update-go-major-version.sh github.com/oschwald/geoip2-golang 2
Additional Context
Go Semantic Import Versioning
From Go Modules v2+ documentation:
If a module is version v2 or higher, the major version of the module must be included as a /vN at the end of the module paths used in go.mod files and in the package import path.
This is a fundamental requirement of Go modules, not a limitation or bug. It ensures:
- Clear indication of major version in code
- Ability to import multiple major versions simultaneously
- Explicit acknowledgment of breaking changes
Similar Past Issues
This is a common pitfall when updating Go modules. Other examples in the Go ecosystem:
gopkg.inpackages (use/v2,/v3suffixes)github.com/go-chi/chi→github.com/go-chi/chi/v5github.com/gorilla/mux→github.com/gorilla/mux/v2(if they release one)
Why the Duplicate Entry?
The duplicate in go.mod likely occurred because:
- Renovate added the v2 dependency
- A merge conflict or concurrent edit preserved an old v2 entry
go mod tidywas not run after the merge- The duplicate doesn't cause an error (Go just ignores duplicates)
However, the real issue is the import path mismatch, not the duplicate.
Conclusion
This is a textbook case of incomplete Go module major version migration. The fix is straightforward but requires manual code changes that automation tools like Renovate cannot safely perform.
Estimated Time to Fix: 10-15 minutes
Risk Level: Low (fix is well-defined and testable)
Priority: High (blocks CI/CD and potentially other workflows)
References
- Go Modules: v2 and Beyond
- Go Module Reference
- geoip2-golang v2 Release Notes
- Renovate Go Modules Documentation
- Failed GitHub Actions Run
- PR #396: Update geoip2-golang to v2
Report generated by GitHub Copilot (Claude Sonnet 4.5)