{"record":{"id":"0790c1e8431dfef0","repo":"unknwon/the-way-to-go_ZH_CN","slug":"error-occurred-err-error","errorCode":null,"errorMessage":"\"ERROR occurred:\" + err.Error()","messagePattern":"\"ERROR occurred:\" \\+ err\\.Error\\(\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"eBook/13.2.md","lineNumber":55,"sourceCode":"一个检查程序是否被已知用户启动的具体例子：\n\n```go\nvar user = os.Getenv(\"USER\")\n\nfunc check() {\n\tif user == \"\" {\n\t\tpanic(\"Unknown user: no value for $USER\")\n\t}\n}\n```\n\n可以在导入包的 `init()` 函数中检查这些。\n\n当发生错误必须中止程序时，`panic()` 可以用于错误处理模式：\n\n```go\nif err != nil {\n\tpanic(\"ERROR occurred:\" + err.Error())\n}\n```\n\n<u>Go panicking</u>：\n\n在多层嵌套的函数调用中调用 `panic()`，可以马上中止当前函数的执行，所有的 `defer` 语句都会保证执行并把控制权交还给接收到 panic 的函数调用者。这样向上冒泡直到最顶层，并执行（每层的） `defer`，在栈顶处程序崩溃，并在命令行中用传给 `panic()` 的值报告错误情况：这个终止过程就是 *panicking*。\n\n标准库中有许多包含 `Must` 前缀的函数，像 `regexp.MustComplie()` 和 `template.Must()`；当正则表达式或模板中转入的转换字符串导致错误时，这些函数会 `panic()`。\n\n不能随意地用 `panic()` 中止程序，必须尽力补救错误让程序能继续执行。\n\n## 链接\n\n- [目录](directory.md)\n- 上一节：[错误处理](13.1.md)\n- 下一节：[从 panic 中恢复 (recover)](13.3.md)\n","sourceCodeStart":37,"sourceCodeEnd":72,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/13.2.md#L37-L72","documentation":"The canonical error-to-panic idiom shown in section 13.2: if err != nil { panic(\"ERROR occurred:\" + err.Error()) }. It is presented as the last-resort branch when a recoverable path does not exist; the same section explicitly warns not to use panic casually ('不能随意地用 panic() 中止程序') and to try to remedy errors first.","triggerScenarios":"Any error value reaching this branch — typically a failed file open, missing configuration, or failed connection during program setup where the author chose termination over propagating the error up the stack.","commonSituations":"Startup-phase code in main/init (config load, DB connect) where error plumbing was shortcut; third-party libraries that panic instead of returning error values, forcing callers to defend with recover.","solutions":["Return the error to the caller instead: add error to the signature and wrap with fmt.Errorf for context","If it is genuinely fatal startup code, use log.Fatalf(\"ERROR occurred: %v\", err) for a clean, timestamped exit","Use %v/%w formatting instead of string concatenation so the cause stays inspectable","When a dependency panics like this, wrap the call site with a deferred recover and convert the panic value to an error"],"exampleFix":"// before\nif err != nil {\n    panic(\"ERROR occurred:\" + err.Error())\n}\n\n// after\nif err != nil {\n    return fmt.Errorf(\"ERROR occurred: %w\", err)\n}\n// or, at top level only:\nif err != nil { log.Fatalf(\"ERROR occurred: %v\", err) }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// boundary guard around code that uses the panic idiom\ndefer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"recovered: %v\", r)\n    }\n}()\nresult = riskyCall()","preventionTips":["Propagate errors up the call chain instead of panicking mid-library","Centralize exit decisions in main; panic only for programmer invariants","Use %w wrapping so callers can errors.Is/As the cause at the boundary"],"tags":["go","error-handling","panic","idiom"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}