Why didn't my goroutines run?

Read the explanation
What if

main starts three goroutines and returns. None of them get to print.

Predict first

main starts three goroutines with go worker(i), then returns. What gets printed?

012345678main: go worker(1)go 1main: go worker(2)go 2main: go worker(3)go 3printreturntime.Sleepnever printstime.Sleepnever printstime.Sleepnever prints

Tap any block to see what that thread is doing.

  • Running
  • Waiting / parked
  • Skipped
Step 1/4

go worker(1) starts a goroutine and returns at once. main doesn't wait for it.

1func worker(id int) {2    time.Sleep(10 * time.Millisecond) // some work3    fmt.Println("worker", id, "done")4}5 6func main() {7    for i := 1; i <= 3; i++ {8        go worker(i)9    }10    fmt.Println("main returns")11} // the program ends here, finished or not

Explanation

What just happened

go worker(i) starts a goroutine and returns right away. main didn’t wait for anything: it printed and returned while all three workers were still in time.Sleep. In Go, main returning ends the program, so the workers died mid-sleep. Their Println never ran.

Nothing tells you. No panic, no warning, exit code 0.

Try the what-if switch

Why it works like this

Goroutines are cheap and have no owner. Go doesn’t track which ones you still care about, so it can’t wait for them for you. Waiting is your job: a WaitGroup, a channel, or errgroup.

Watch out

Call wg.Add before go, never inside the goroutine. The workers’ print order changes from run to run; only “all done” is sure to come last.

Common questions

Why does my goroutine not print anything?

Because main returned first. When main returns, the whole program exits at once, and Go doesn't wait for other goroutines. There's no error and the exit code is 0.

How do I wait for goroutines to finish?

Use a sync.WaitGroup: call wg.Add(1) before each go, defer wg.Done() in the goroutine, and wg.Wait() in main. Since Go 1.25, wg.Go(f) does the Add and Done for you.

Can I call wg.Add inside the goroutine?

No. The goroutine may not have started when main reaches wg.Wait(), so the counter is still 0 and Wait returns at once. Call wg.Add before the go statement.

Verified: this timeline matches a real program, checked in CI on Go 1.26 and 1.27. How we verify. Unclear or wrong? Tell us