Go "DATA RACE" - go test -race Fails the Build in CI
Go’s race detector (go test -race) flagged concurrent, unsynchronized access to shared memory: one goroutine wrote while another read or wrote the same location without a lock or channel. It is a real concurrency bug, not flake.
What this error means
A test run with -race prints "WARNING: DATA RACE" with two stacks - the conflicting read and write - and exits non-zero. The same tests pass without -race, because the race only fails the build when the detector is on.
==================
WARNING: DATA RACE
Write at 0x00c0000b4010 by goroutine 8:
main.(*Counter).Inc()
counter.go:14 +0x44
Previous read at 0x00c0000b4010 by goroutine 7:
main.(*Counter).Value()
counter.go:18 +0x38
==================Common causes
Shared variable accessed without synchronization
Multiple goroutines read/write the same variable, map, or struct field with no mutex or channel coordinating them. The detector catches the unsynchronized overlap.
Concurrent map access
Go maps are not safe for concurrent use. A goroutine writing a map while another reads it races (and can also panic with "concurrent map writes").
How to fix it
Guard shared state with a mutex
Serialize access so reads and writes cannot overlap.
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 }Prefer channels or atomics where they fit
- Use
sync/atomicfor simple counters instead of a mutex. - Pass ownership via channels rather than sharing memory.
- Keep
-racein CI so new races fail the build immediately.
How to prevent it
- Run
go test -race ./...in CI. - Protect shared state with mutexes, atomics, or channels.
- Never read/write a plain map from multiple goroutines.