{"record":{"id":"3796e731463526b8","repo":"uber-go/zap","slug":"panic-v-3796e7","errorCode":null,"errorMessage":"PANIC=%v","messagePattern":"PANIC=(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"zapcore/field.go","lineNumber":227,"sourceCode":"\tfor i := range fields {\n\t\tfields[i].AddTo(enc)\n\t}\n}\n\nfunc encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr error) {\n\t// Try to capture panics (from nil references or otherwise) when calling\n\t// the String() method, similar to https://golang.org/src/fmt/print.go#L540\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\t// If it's a nil pointer, just say \"<nil>\". The likeliest causes are a\n\t\t\t// Stringer 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(stringer); 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\", err)\n\t\t}\n\t}()\n\n\tenc.AddString(key, stringer.(fmt.Stringer).String())\n\treturn nil\n}\n","sourceCodeStart":209,"sourceCodeEnd":234,"githubUrl":"https://github.com/uber-go/zap/blob/bbd4ecbd8760678fdbac94c93d9aca8069c83b2f/zapcore/field.go#L209-L234","documentation":"zapcore/field.go's encodeStringer recovers from panics raised while calling String() on a value passed with zap.Stringer (or similar). If String() panics, the field is encoded with the message \"PANIC=%v\" containing the recovered panic value rather than letting the panic escape the logging call.","triggerScenarios":"Logging a type implementing fmt.Stringer whose String() method panics — nil pointer receiver dereference, index out of range, or calling methods on zero-value fields — via zap.Stringer(key, v).","commonSituations":"Stringers that dereference nested pointers which are nil, stringers over structs not yet initialized, mutex-guarded types whose String() is called from a context where state is invalid.","solutions":["Make the String() method panic-safe: nil-check the receiver and any pointers it dereferences.","Inspect the encoded PANIC=%v value in logs to identify the panicking Stringer and its panic reason.","Stop logging the offending type with zap.Stringer until its String() is fixed (or log safe fields explicitly)."],"exampleFix":"// before\nfunc (u *User) String() string { return u.Name } // panics when u is nil\n// after\nfunc (u *User) String() string {\n    if u == nil { return \"<nil>\" }\n    return u.Name\n}","handlingStrategy":"type-guard","validationCode":"func safeString(v fmt.Stringer) (s string) {\n    defer func() { if recover() != nil { s = \"<panic in String()>\" } }()\n    return v.String()\n}\nlogger.Info(\"user\", zap.String(\"user\", safeString(u)))","typeGuard":"func stringerSafe(v any) (fmt.Stringer, bool) {\n    s, ok := v.(fmt.Stringer)\n    if !ok { return nil, false }\n    safe := func() (s string) {\n        defer func() { if recover() != nil { s = \"<nil>\" } }()\n        return s0(s)\n    }\n    _ = safe // wrap in your own safe Stringer type\n    return safeStringer{s}, true\n}","tryCatchPattern":null,"preventionTips":["Write String() implementations that handle nil receivers and nil nested pointers.","Avoid logging types whose String() depends on uninitialized state.","Grep production logs for \"PANIC=\" to detect failing Stringers early."],"tags":["panic-recovery","stringer","zapcore"],"backgroundTag":"panic-in-stringer-string","analyzedSha":"bbd4ecbd8760678fdbac94c93d9aca8069c83b2f","analyzedAt":"2026-08-31T13:01:40.228Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}