{"record":{"id":"40d1f6173c246e26","repo":"apache/beam","slug":"logger-cannot-be-nil","errorCode":null,"errorMessage":"Logger cannot be nil","messagePattern":"Logger cannot be nil","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/log/log.go","lineNumber":75,"sourceCode":"}\n\nvar logger atomic.Value\n\n// concreteLogger works around atomic.Value's requirement that the type\n// be identical for all callers.\ntype concreteLogger struct {\n\tLogger\n}\n\nfunc init() {\n\tlogger.Store(&concreteLogger{&Structural{}})\n}\n\n// SetLogger sets the global Logger. Intended to be called during initialization\n// only.\nfunc SetLogger(l Logger) {\n\tif l == nil {\n\t\tpanic(\"Logger cannot be nil\")\n\t}\n\tlogger.Store(&concreteLogger{l})\n}\n\n// Output logs the given message to the global logger. Calldepth is the count\n// of the number of frames to skip when computing the file name and line number.\nfunc Output(ctx context.Context, sev Severity, calldepth int, msg string) {\n\tlogger.Load().(Logger).Log(ctx, sev, calldepth+1, msg) // +1 for this frame\n}\n\n// User-facing logging functions.\n\n// Debug writes the fmt.Sprint-formatted arguments to the global logger with\n// debug severity.\nfunc Debug(ctx context.Context, v ...any) {\n\tOutput(ctx, SevDebug, 1, fmt.Sprint(v...))\n}\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/log/log.go#L57-L93","documentation":"SetLogger in the Beam Go log package panics if called with a nil Logger. The global logger must always have a valid implementation; installing nil would cause nil dereferences in every later log call, so it is rejected up front. It is intended for initialization-time use only.","triggerScenarios":"Calling log.SetLogger(nil), or passing a typed-nil (e.g. a nil *MyLogger wrapped in the Logger interface) which is non-nil as an interface but nil as a pointer.","commonSituations":"Initializing logging from a config factory that returned nil on failure; forgetting to construct the logger before registering it; the classic typed-nil-interface pitfall in Go.","solutions":["Construct a real Logger implementation before calling SetLogger (e.g. log.NewLogger(...) or a slog/zap adapter).","Guard with an interface-nil check plus reflect-based typed-nil check if the logger comes from an external factory.","Handle the factory error path so a failed logger construction aborts initialization instead of returning nil."],"exampleFix":"// before\nvar myLog *MyLogger\nlog.SetLogger(myLog) // typed nil, panics\n// after\nif myLog == nil { myLog = NewMyLogger() }\nlog.SetLogger(myLog)","handlingStrategy":"type-guard","validationCode":"if logger == nil {\n    return errors.New(\"cannot install nil logger\")\n}","typeGuard":"func isNilLogger(l log.Logger) bool {\n    if l == nil { return true }\n    v := reflect.ValueOf(l)\n    switch v.Kind() {\n    case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Interface:\n        return v.IsNil()\n    }\n    return false\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"SetLogger rejected the logger: %v\", r)\n    }\n}()","preventionTips":["Handle factory errors so a failed logger construction never returns nil.","Beware typed-nil pointers wrapped in interfaces — check the concrete value too.","Install a default logger at program start before any other init code."],"tags":["go","apache-beam","logging","nil-argument","panic"],"backgroundTag":"null-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}