Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.