Fundamentals 4 min read

Why Go 1.23’s New Iterator Breaks Nested Loops and How to Spot It

The article reveals a bug in Go 1.23’s newly added iterator that corrupts results in three‑level nested loops, demonstrates the issue with a reproducible code sample, explains the underlying cause, offers a temporary compile‑flag workaround, and notes the imminent fix.

BirdNest Tech Talk
BirdNest Tech Talk
BirdNest Tech Talk
Why Go 1.23’s New Iterator Breaks Nested Loops and How to Spot It

Reproducing the nested iterator bug in Go 1.23.2

The following program uses the new slices.Values iterator three times, each inside a nested for loop. It concatenates every element from the innermost loop into a string and returns the final result.

package main

import (
    "fmt"
    "slices"
)

func Bug(s1, s2, s3 []string) string {
    var c1 string
    for v1 := range slices.Values(s1) {
        var c2 string
        for v2 := range slices.Values(s2) {
            var c3 string
            for v3 := range slices.Values(s3) {
                c3 = c3 + v3
            }
            c2 = c2 + v2 + c3
        }
        c1 = c1 + v1 + c2
    }
    return c1
}

func main() {
    got := Bug([]string{"1", "2", "3"}, []string{"a", "b", "c"}, []string{"A", "B", "C"})
    want := "1aABCbABCcABC2aABCbABCcABC3aABCbABCcABC"
    if got != want {
        fmt.Println(fmt.Errorf("got %v, want %v", got, want))
    }
}

With the expected concatenation 1aABCbABCcABC2aABCbABCcABC3aABCbABCcABC, the actual output produced by Go 1.23.2 differs (see screenshot). The discrepancy appears only when iterators are nested; a single‑level iterator works correctly.

Go iterator bug output
Go iterator bug output

Root cause and temporary mitigation

Investigation of the Go compiler source shows that the optimizer inlines the iterator helper functions. Inlining changes the lifetimes of the temporary variables that hold the iterator state, causing the innermost loop to reuse the same buffer across iterations. This leads to missing characters in the final string.

Compiling with inlining disabled prevents the incorrect reuse: go build -gcflags='-l' . The flag -gcflags='-l' disables function inlining, restoring the correct output. However, disabling inlining is unsuitable for production because it degrades performance.

Fix and broader implications

The bug was filed immediately after discovery, and a patch that adjusts the iterator implementation to preserve separate state per call was submitted the next day. The patch is slated for inclusion in the first minor release after 1.23.2.

Prior to this regression, many experienced Go developers had already expressed concerns about the complexity and maintainability of the iterator feature introduced in Go 1.23. The regression reinforces the risk of adding highly clever, low‑level optimizations without exhaustive testing, especially when those optimizations interact with nested constructs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DebuggingGoCompiler FlagsGo 1.23Iterator Bug
BirdNest Tech Talk
Written by

BirdNest Tech Talk

Author of the rpcx microservice framework, original book author, and chair of Baidu's Go CMC committee.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.