Why do my goroutines see stale or repeated keys when ranging over a map and modifying it at the same time?

1 week ago 4
ARTICLE AD BOX

I’m experimenting with Go’s for range loop and goroutines, and I ran into behavior I can’t explain.
This example prints inconsistent or duplicated values:

package main import ( "fmt" "sync" ) func main() { m := map[int]string{ 1: "one", 2: "two", } var wg sync.WaitGroup for k, v := range m { wg.Add(1) // modifying the map inside the loop (I know it's unsafe — but I want to understand the behaviour) if k == 1 { m[3] = "three" } go func(k int, v string) { defer wg.Done() fmt.Println("goroutine:", k, v) }(k, v) } wg.Wait() }

Output varies per run:

goroutine: 1 one goroutine: 2 two goroutine: 2 two

Or:

goroutine: 1 one goroutine: 2 two goroutine: 3 three // I never actually ranged over this key

Or even:

goroutine: 1 one goroutine: 1 one

Why does range m seem to produce inconsistent keys when the map is modified during iteration?

Does Go internally rehash, resize, or re-randomize map buckets during iteration?

Does the loop variable get copied before or after a rehash?

Is this behaviour guaranteed, undefined, or just an artifact of how map iteration works in Go 1.22+?

Why do goroutines sometimes see duplicate keys even though range supposedly visits each element once?

Read Entire Article