uber-go/zap · error
ce.Message
Error message
ce.Message
What it means
CheckWriteAction.OnWrite implements the post-write hook: if the action is WriteThenPanic, it panics with the checked entry's message after the log entry has been written. This is the configured behavior for Panic-level logging — the message logged is also the panic value.
Source
Thrown at zapcore/entry.go:196
// WriteThenNoop indicates that nothing special needs to be done. It's the
// default behavior.
WriteThenNoop CheckWriteAction = iota
// WriteThenGoexit runs runtime.Goexit after Write.
WriteThenGoexit
// WriteThenPanic causes a panic after Write.
WriteThenPanic
// WriteThenFatal causes an os.Exit(1) after Write.
WriteThenFatal
)
// OnWrite implements the OnWrite method to keep CheckWriteAction compatible
// with the new CheckWriteHook interface which deprecates CheckWriteAction.
func (a CheckWriteAction) OnWrite(ce *CheckedEntry, _ []Field) {
switch a {
case WriteThenGoexit:
runtime.Goexit()
case WriteThenPanic:
panic(ce.Message)
case WriteThenFatal:
exit.With(1)
}
}
var _ CheckWriteHook = CheckWriteAction(0)
// CheckPreWriteHook is a function that transforms an Entry and its Fields
// before they are written to cores. Register one on a CheckedEntry with the
// Before method.
//
// Pre-write hooks run in the order they were added, before any Core's Write
// method is called. They may modify the Entry and Fields freely.
type CheckPreWriteHook func(Entry, []Field) (Entry, []Field)
// CheckedEntry is an Entry together with a collection of Cores that have
// already agreed to log it.
//View on GitHub (pinned to bbd4ecbd87)
Solutions
- If the panic is unintended, log with logger.Error instead of logger.Panic, or configure the level action as WriteThenFatal/WriteThenNoop.
- Wrap entry points (HTTP handlers, goroutine bodies) with defer recover() where Panic-level logging is expected.
- If you need the panic value, recover and type-assert — it is exactly the string passed to logger.Panic.
Example fix
// before
logger.Panic("cache unavailable") // panics process
// after
logger.Error("cache unavailable") Defensive patterns
Strategy: try-catch
Validate before calling
// Prefer Error level if panicking is undesired:
logger.Error("cache unavailable") // instead of logger.Panic(...) Try / catch
func safeHandler(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
if msg, ok := rec.(string); ok {
logger.Error("recovered panic-level log", zap.String("msg", msg))
}
http.Error(w, "internal error", 500)
}
}()
h(w, r)
}
} Prevention
- Install a recover() middleware/decorator wherever Panic-level logging is used.
- Reserve logger.Panic for truly unrecoverable conditions only.
- Prefer logger.Fatal/exit hooks only when process termination is intended.
When it happens
Trigger: Any logger call at Panic level (logger.Panic(...), logger.Check(zapcore.PanicLevel, msg).Write(...)) with a core/hook configured with CheckWriteAction(WriteThenPanic) — the write completes, then panic(ce.Message) runs.
Common situations: Applications using zap's Panic-level for unrecoverable conditions, relying on a recover() in a top-level handler (HTTP middleware, worker loops) to convert the panic into a 500/retry; panics escaping tests when recover isn't set.
Related errors
- can't unmarshal a nil *Level
- PANIC=%v
- PANIC=%v
- invalid increase level, as level %q is allowed by increased
- underlying error from the wrapped (*Logger, error) call
AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31).
Data as JSON: /api/errors/94adfd4d52030bcd.
Report an issue: GitHub.