{"record":{"id":"59813289515d2823","repo":"uber-go/zap","slug":"panic-v","errorCode":null,"errorMessage":"PANIC=%v","messagePattern":"PANIC=(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"zapcore/error.go","lineNumber":60,"sourceCode":"//\t  \"errorVerbose\": fmt.Sprintf(\"%+v\", err),\n//\t  \"errorCauses\": [\n//\t    ...\n//\t  ],\n//\t}\nfunc encodeError(key string, err error, enc ObjectEncoder) (retErr error) {\n\t// Try to capture panics (from nil references or otherwise) when calling\n\t// the Error() method\n\tdefer func() {\n\t\tif rerr := recover(); rerr != nil {\n\t\t\t// If it's a nil pointer, just say \"<nil>\". The likeliest causes are a\n\t\t\t// error that fails to guard against nil or a nil pointer for a\n\t\t\t// value receiver, and in either case, \"<nil>\" is a nice result.\n\t\t\tif v := reflect.ValueOf(err); v.Kind() == reflect.Pointer && v.IsNil() {\n\t\t\t\tenc.AddString(key, \"<nil>\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tretErr = fmt.Errorf(\"PANIC=%v\", rerr)\n\t\t}\n\t}()\n\n\tbasic := err.Error()\n\tenc.AddString(key, basic)\n\n\tswitch e := err.(type) {\n\tcase errorGroup:\n\t\treturn enc.AddArray(key+\"Causes\", errArray(e.Errors()))\n\tcase fmt.Formatter:\n\t\tverbose := fmt.Sprintf(\"%+v\", e)\n\t\tif verbose != basic {\n\t\t\t// This is a rich error type, like those produced by\n\t\t\t// github.com/pkg/errors.\n\t\t\tenc.AddString(key+\"Verbose\", verbose)\n\t\t}\n\t}\n\treturn nil","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/uber-go/zap/blob/bbd4ecbd8760678fdbac94c93d9aca8069c83b2f/zapcore/error.go#L42-L78","documentation":"zapcore/error.go's encodeError recovers from panics raised while calling err.Error() (or MarshalLogObject on the error) during field encoding. Instead of crashing the logger, it encodes the string \"PANIC=%v\" with the recovered value as the field's value.","triggerScenarios":"Logging an error whose Error() method panics — e.g. nil pointer dereference inside a custom error's Error(), or a panic thrown by the error's MarshalLogObject implementation, passed via zap.Error(err) or zap.NamedError.","commonSituations":"Custom error types with methods dereferencing nil state, lazy errors wrapping values that became nil, third-party error types with buggy Error() implementations being logged.","solutions":["Fix the custom error type so Error() cannot panic (nil-check wrapped errors and internal fields).","Audit logged values: ensure zap.Error is not given an uninitialized/zero-value error struct whose Error() dereferences nil.","Check the log output for the PANIC=%v message — the %v content identifies the panic cause (e.g. runtime error: invalid memory address)."],"exampleFix":"// before\nfunc (e *MyErr) Error() string { return e.msg } // panics if e is nil\n// after\nfunc (e *MyErr) Error() string {\n    if e == nil { return \"<nil>\" }\n    return e.msg\n}","handlingStrategy":"type-guard","validationCode":"func safeLogError(logger *zap.Logger, err error) {\n    if err == nil { return }\n    func() {\n        defer func() { _ = recover() }()\n        _ = err.Error()\n    }() // reaches here safely only if Error() doesn't panic\n    logger.Error(\"op failed\", zap.Error(err))\n}","typeGuard":"func errSafeToLog(err error) (safe error, ok bool) {\n    ok = func() (ok bool) {\n        defer func() { if recover() != nil { ok = false } }()\n        _ = err.Error()\n        return true\n    }()\n    if ok { return err, true }\n    return errors.New(\"<unloggable error>\"), false\n}","tryCatchPattern":null,"preventionTips":["Make custom error types' Error() methods nil-safe and free of side effects.","Never implement Error() with lazy dereferences of unset wrapped errors.","Scan logs periodically for \"PANIC=\" markers to find buggy error types."],"tags":["panic-recovery","error-encoding","zapcore"],"backgroundTag":"panic-in-error-error","analyzedSha":"bbd4ecbd8760678fdbac94c93d9aca8069c83b2f","analyzedAt":"2026-08-31T13:01:40.228Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}