Appendix C: Reading the Compiler
Go’s diagnostics are terse. There is no error code, no explanation, no --explain
subcommand, and usually one line. That takes getting used to if you have been
reading Rust’s, and the compensation is that the messages say what is wrong in
words rather than in jargon, and there are not many distinct ones to learn.
The format is file:line:column: message. The compiler stops after ten and says
too many errors, so a long list usually means one mistake near the top; fix
that and rebuild before reading the rest.
Every message below was produced by building the file of that name in
examples/errors.
Errors you will see in the first week
Declared and not used. An unused local variable is an error. Assign it to
_ if you really want it, or delete it.
unusedvar/main.go:7:2: declared and not used: total
Imported and not used. Same rule for imports. Let your editor manage the
import block with goimports.
unusedimport/main.go:5:2: "os" imported and not used
No new variables on the left side of :=. You used := twice on the same
name. The second one should be =.
shortdecl/main.go:7:7: no new variables on left side of :=
Mismatched types. Go promotes nothing. Convert explicitly with float64(n).
mismatch/main.go:8:14: invalid operation: n * f (mismatched types int and float64)
Undefined. A typo, a missing import, or a name that is lower-case in another package and therefore not exported.
undefined/main.go:6:14: undefined: total
Missing return. Go requires the end of a function with results to be
unreachable. An if/else if chain with no final else can fall off the end
even when you know it cannot, so add the else or a final return.
missingreturn/main.go:9:1: missing return
Assignment mismatch. You took one value from a function that returns two,
which almost always means you forgot the err.
assignmismatch/main.go:9:7: assignment mismatch: 1 variable but os.Open returns 2 values
Wrong arguments. Note that the compiler prints what you passed and what was wanted.
argcount/main.go:8:18: not enough arguments in call to add
have (number)
want (int, int)
argcount/main.go:9:24: too many arguments in call to add
have (number, number, number)
want (int, int)
argcount/main.go:10:21: cannot use "two" (untyped string constant) as int value in argument to add
Does not implement. The message names the missing method. That is the answer. Check the spelling, the signature, and whether the method has a pointer receiver while you passed a value.
notimpl/main.go:15:17: cannot use Square{…} (value of struct type Square) as Shape value in variable declaration: Square does not implement Shape (missing method Perimeter)
Cannot assign to a struct field in a map. Map elements are not addressable. Store a pointer, or read the value out, modify it, and put it back.
unaddressable/main.go:7:2: cannot assign to struct field m["a"].X in map
Non-declaration statement outside function body. := at package level.
Use var or const.
outsidefunc/main.go:5:1: syntax error: non-declaration statement outside function body
Range over an int takes one variable. There is no index and value to unpack; the single variable is the number.
badrange/main.go:7:9: range over n (variable of type int) permits only one iteration variable
Panics
A panic is a run-time failure. The message is on the first line and everything after it is the stack, most recent call first, with the failing line at the top.
Index out of range. The message gives the index and the length.
panic: runtime error: index out of range [5] with length 3
Slice bounds out of range. Slicing may go up to the capacity, so this one reports capacity rather than length.
panic: runtime error: slice bounds out of range [:9] with capacity 3
Nil pointer dereference. Section 5.3.
panic: runtime error: invalid memory address or nil pointer dereference
Assignment to entry in nil map. You forgot the make. Section 7.3.
panic: assignment to entry in nil map
Interface conversion. A type assertion that was wrong. Use the comma-ok form so it reports rather than panics.
panic: interface conversion: interface {} is string, not int
Deadlock. Every goroutine is blocked. The runtime can only detect this when nothing at all can run, so a program with a live goroutine somewhere will hang instead of reporting.
fatal error: all goroutines are asleep - deadlock!
Vet
go vet reports mistakes that are legal Go. Run it with your tests; go test
already runs some of its checks.
Format verbs that do not match their arguments. This is the check that pays for the others.
vet/printf/main.go:7:14: fmt.Printf format %d has arg name of wrong type string
vet/printf/main.go:8:14: fmt.Printf format %s reads arg #1, but call has 0 args
A copied lock. Section 5.4.
vet/copylock/main.go:13:13: show passes lock by value: goexamples/errors/vet/copylock.Registry contains sync.Mutex
A discarded cancel function. Section 11.6.
vet/lostcancel/main.go:10:7: the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak
A string(int) conversion, which gives a one-rune string rather than
digits. Section 2.4.
conversion from int to string yields a string of one rune, not a string of digits
When the message is not enough
go doc <package>.<Name> prints the documentation for anything you are unsure
about, offline and instantly, and it is faster than a search engine.
go build ./... builds everything rather than one package, which matters when
the error is in a file you did not touch.
gofmt on a file with a syntax error will refuse to format it, so a file
your editor stops reformatting is a file that no longer parses. That is often
the fastest signal that you left out a brace.