Searches such as ok golang, golang ok, comma ok, comma ok golang, golang comma ok, comma ok idiom golang, golang comma ok idiom, and go comma ok idiom all point at the same pattern: a two-value assignment where the second value is a bool usually named ok. In Go that shows up on map lookups, type assertions, and receives from channels. It is different from the common (T, error) pattern where the second value is an error—you still use two results, but ok golang tutorials almost always mean the boolean comma ok idiom, not err != nil alone.
Tested with Go 1.24 on Linux.
Map lookup: value, ok := m[key]
If the key exists, ok is true even when the stored value is the zero value (for example 0 or ""). That is why you must use ok instead of only checking v.
package main
import "fmt"
func main() {
m := map[string]string{"method": "POST", "empty": ""}
if v, ok := m["method"]; ok {
fmt.Println(v)
}
if v, ok := m["empty"]; ok {
fmt.Printf("zero value but present: %q ok=%v\n", v, ok)
}
if _, ok := m["missing"]; !ok {
fmt.Println("missing")
}
}Run locally: you should see POST, a line showing the empty string with ok=true, then missing.
Type assertion: t, ok := x.(T)
A single-value assertion x.(T) panics when the dynamic type does not match. The golang ok idiom form t, ok := x.(T) sets ok to false instead.
package main
import "fmt"
func main() {
var v any = 42
if s, ok := v.(string); ok {
fmt.Println(s)
} else {
fmt.Printf("not a string, type=%T\n", v)
}
}You should see not a string, type=int.
Channel receive: v, ok := <-ch
When a channel is closed and drained, a receive returns the element zero value and ok == false. That is how you distinguish “real zero value still coming” from “channel closed” on an unbuffered or drained channel—often you instead for v := range ch when the sender closes after sending everything (channels).
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
v1, ok1 := <-ch
v2, ok2 := <-ch
_, ok3 := <-ch
fmt.Println(v1, ok1, v2, ok2, ok3)
}You should see 1 true 2 true false (third receive sees closed, empty channel).
Related: (T, error) is not quite “comma ok”
Many APIs return (result, error). The usual pattern is if err := f(); err != nil or v, err := f(); if err != nil. The second value is an error, not a bool named ok—but it is still a two-result check people group with defensive Go style.
package main
import (
"errors"
"fmt"
)
func half(n int) (int, error) {
if n%2 != 0 {
return 0, errors.New("odd")
}
return n / 2, nil
}
func main() {
if v, err := half(4); err == nil {
fmt.Println(v)
}
}You should see 2.
Summary
The comma ok idiom golang pattern is value, ok := … ; ok for maps, type assertions, and channel receives, where ok tells you whether the operation really succeeded. Go comma ok idiom posts match golang comma ok searches: same syntax, three main sites in the language. For concurrency context see goroutines and concurrency overview. Remember ok is only a name you choose; readability is why ok golang shows up so often in examples.

