unknwon/the-way-to-go_ZH_CN · error

bad end

Error message

bad end

What it means

Example 13.3 (panic_recover.go): badCall() panics with 'bad end'; test() installs a deferred closure that recovers and prints 'Panicing bad end'. It demonstrates that recover stops the unwinding, deferred functions still execute, and the statement after badCall() ('After bad call') is never reached.

Source

Thrown at eBook/13.3.md:44

`log` 包实现了简单的日志功能:默认的 log 对象向标准错误输出中写入并打印每条日志信息的日期和时间。除了 `Println` 和 `Printf` 函数,其它的致命性函数都会在写完日志信息后调用 `os.Exit(1)`,那些退出函数也是如此。而 Panic 效果的函数会在写完日志信息后调用 `panic()`;可以在程序必须中止或发生了临界错误时使用它们,就像当 web 服务器不能启动时那样(参见 [15.4 节](15.4.md) 中的例子)。

log 包用那些方法 (methods) 定义了一个 `Logger` 接口类型,如果你想自定义日志系统的话可以参考 [http://golang.org/pkg/log/#Logger](http://golang.org/pkg/log/#Logger) 。

这是一个展示 `panic()`,`defer` 和 `recover()` 怎么结合使用的完整例子:

示例 13.3 [panic_recover.go](examples/chapter_13/panic_recover.go):

```go
// panic_recover.go
package main

import (
	"fmt"
)

func badCall() {
	panic("bad end")
}

func test() {
	defer func() {
		if e := recover(); e != nil {
			fmt.Printf("Panicing %s\r\n", e)
		}
	}()
	badCall()
	fmt.Printf("After bad call\r\n") // <-- would not reach
}

func main() {
	fmt.Printf("Calling test\r\n")
	test()
	fmt.Printf("Test completed\r\n")
}
```

View on GitHub (pinned to 7a54d34d36)

Solutions

  1. Keep the deferred recover in the same function that transitively calls badCall
  2. If badCall runs in a goroutine, put its own deferred recover inside that goroutine's function
  3. Replace the panic with a returned error when the failure is an expected condition
  4. After recover, explicitly return any default values — code below the panic point never resumes

Example fix

// before
go badCall() // parent recover cannot catch this; process crashes

// after
go func() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Printf("Panicing %s\r\n", e)
        }
    }()
    badCall()
}()
Defensive patterns

Strategy: try-catch

Try / catch

// the canonical pattern from the source — recover in the SAME goroutine
func test() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Printf("Panicing %s\r\n", e)
        }
    }()
    badCall()
    fmt.Printf("After bad call\r\n") // unreached if badCall panics
}

Prevention

When it happens

Trigger: Calling badCall() (or any equivalent panicking function) from a location that lacks the deferred recover; or calling it from a different goroutine — recover only works within the panicking goroutine, so a parent's recover cannot catch a child goroutine's panic.

Common situations: Students restructuring the demo and dropping the defer; spawning badCall with 'go' and expecting the caller's recover to fire (it cannot, and the program crashes); assuming execution resumes after the panic point within the same function (it does not — only the deferred wrapper continues).

Related errors


AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15). Data as JSON: /api/errors/9d3ec39ced90da70. Report an issue: GitHub.