Go "DATA RACE" - Fix go test -race Detector Failures in CI
The race detector (go test -race) caught two goroutines accessing the same memory concurrently, at least one of them writing, with no synchronization. This is a real bug - data races are undefined behavior in Go.
What this error means
go test -race prints WARNING: DATA RACE with the conflicting read and write goroutine stacks, then fails the test. Without -race the same test may pass, which is why it surfaces only in a race-enabled CI run.
==================
WARNING: DATA RACE
Write at 0x00c0000b4010 by goroutine 8:
github.com/yourorg/app.(*Counter).Inc()
counter.go:14 +0x44
Previous read at 0x00c0000b4010 by goroutine 7:
github.com/yourorg/app.(*Counter).Value()
counter.go:18 +0x38
==================Common causes
Unsynchronized shared state
Multiple goroutines read and write the same variable, map, or struct field without a mutex, channel, or atomic, so the accesses race.
Concurrent map access
Reading and writing a built-in map from different goroutines is a classic race the detector flags (and can also panic at runtime).
How to fix it
Add synchronization at the conflict point
Read the two stacks the detector prints - they name the exact lines. Protect that shared state.
import "sync"
type Counter struct {
mu sync.Mutex
n int
}
func (c *Counter) Inc() { c.mu.Lock(); c.n++; c.mu.Unlock() }
func (c *Counter) Value() int { c.mu.Lock(); defer c.mu.Unlock(); return c.n }Use atomics or channels where appropriate
- For simple counters/flags, use
sync/atomicinstead of a mutex. - For ownership transfer, pass data over a channel rather than sharing it.
- For maps under concurrency, use
sync.Mapor guard with a mutex.
How to prevent it
- Run
go test -racein CI so races fail the build, not production. - Guard all shared mutable state with a mutex, atomic, or channel.
- Treat a DATA RACE as a real bug - it is never safe to ignore.