Go: Multiple-Value in Single-Value Context — How to Fix It
You try to compile your Go code and the compiler says:
multiple-value os.Open() (untyped nil) in single-value context
Or more generally:
multiple-value someFunc() in single-value context
You’re calling a function that returns multiple values but only capturing one.
What causes this
In Go, functions commonly return multiple values — typically a result and an error. This is one of Go’s core patterns. Unlike languages where errors are thrown as exceptions, Go returns them as explicit values.
The compiler enforces that you handle all return values. You can’t just grab the first one and ignore the rest. This is by design — it forces you to deal with errors.
You’ll hit this when:
- You assign a multi-return function to a single variable
- You use a multi-return function directly in an expression (like passing it to
fmt.Printlnas one argument) - You’re coming from a language like Python or JavaScript where you can ignore return values freely
Fix 1: Capture all return values
The standard fix — accept every value the function returns:
// ❌ os.Open returns (*File, error)
f := os.Open("config.json")
// ✅ Capture both values
f, err := os.Open("config.json")
if err != nil {
log.Fatal(err)
}
defer f.Close()
This is the idiomatic Go pattern. Always check the error.
Fix 2: Discard a return value with the blank identifier
If you genuinely don’t need one of the return values, use _:
// ✅ Ignore the error (not recommended for I/O)
f, _ := os.Open("config.json")
// ✅ Ignore the value, keep the error
_, err := os.Open("config.json")
if err != nil {
log.Fatal(err)
}
Use _ sparingly. Ignoring errors is a code smell in Go. It’s acceptable in cases like fmt.Fprintf where the error is rarely meaningful, but for file I/O, network calls, or database operations — always handle the error.
Fix 3: Handle it inline in an if statement
Go lets you combine the assignment and the error check in one line:
// ✅ Short variable declaration in if
if f, err := os.Open("config.json"); err != nil {
log.Fatal(err)
} else {
defer f.Close()
// use f
}
Note that f and err are scoped to the if block in this pattern. If you need f outside the block, use the two-line version from Fix 1.
Fix 4: When using multi-return in function arguments
You can’t pass a multi-return function directly as an argument to another function that expects separate parameters:
// ❌ This won't compile
fmt.Println(strconv.Atoi("42"))
// ✅ Capture first, then pass
val, err := strconv.Atoi("42")
if err != nil {
log.Fatal(err)
}
fmt.Println(val)
The one exception: you can pass a multi-return function to another function that accepts exactly those types as parameters. But this is rare and not worth relying on.
How to prevent it
- Get comfortable with Go’s
value, err :=pattern — you’ll write it hundreds of times per project - Use a linter like
errcheckorgolangci-lintto catch ignored errors - If you find yourself ignoring errors frequently, reconsider your error handling strategy — wrapping errors with
fmt.Errorf("context: %w", err)makes them more useful - IDE support (VS Code with gopls, GoLand) will highlight this error in real time before you even try to compile