{"record":{"id":"c1bd34aeb67c33a7","repo":"nats-io/nats-server","slug":"gsl-nil-channel","errorCode":null,"errorMessage":"gsl: nil channel","messagePattern":"gsl: nil channel","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/gsl/gsl.go","lineNumber":42,"sourceCode":"// interested subscribers. Subscribers can have wildcard subjects to\n// match multiple published subjects.\n\n// Common byte variables for wildcards and token separator.\nconst (\n\tpwc     = '*'\n\tpwcs    = \"*\"\n\tfwc     = '>'\n\tfwcs    = \">\"\n\ttsep    = \".\"\n\tbtsep   = '.'\n\t_EMPTY_ = \"\"\n)\n\n// Sublist related errors\nvar (\n\tErrInvalidSubject    = errors.New(\"gsl: invalid subject\")\n\tErrNotFound          = errors.New(\"gsl: no matches found\")\n\tErrNilChan           = errors.New(\"gsl: nil channel\")\n\tErrAlreadyRegistered = errors.New(\"gsl: notification already registered\")\n)\n\n// SimpleSublist is an alias type for GenericSublist that takes\n// empty values, useful for tracking interest only without any\n// unnecessary allocations.\ntype SimpleSublist = GenericSublist[struct{}]\n\n// NewSimpleSublist will create a simple sublist.\nfunc NewSimpleSublist() *SimpleSublist {\n\treturn &GenericSublist[struct{}]{root: newLevel[struct{}]()}\n}\n\n// A GenericSublist stores and efficiently retrieves subscriptions.\ntype GenericSublist[T comparable] struct {\n\tsync.RWMutex\n\troot  *level[T]\n\tcount uint32","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/gsl/gsl.go#L24-L60","documentation":"ErrNilChan ('gsl: nil channel') is returned when registering a notification/interest watcher with a nil notification channel. registerNotification rejects a nil notify argument (server/sublist.go:174), and the identical sentinel also exists in the server's own sublist package (server/sublist.go:45) with the same message.","triggerScenarios":"Calling NewSublistNotification / notification registration APIs passing nil for the notification channel, e.g. a watcher created without a result channel or after the channel was closed and set to nil.","commonSituations":"Code paths where a results channel is lazily created but registration happens first, watch/interest tracking in tests passing nil, cleanup code nil-ing channels before unregistering notifications.","solutions":["Create the notification channel (make(chan interface{}, size)) before registering the notification.","Check for nil before calling registerNotification and return a clearer caller-side error.","Unregister the old notification before nil-ing/replacing the channel rather than registering with a nil channel."],"exampleFix":"// before\nsl.Notify(n) // n.Chan is nil -> gsl: nil channel\n// after\nn.Chan = make(chan interface{}, 16)\nif err := sl.Notify(n); err != nil {\n    return err\n}","handlingStrategy":"validation","validationCode":"if n == nil || n.Chan == nil {\n    return errors.New(\"notification channel must be non-nil before registration\")\n}","typeGuard":null,"tryCatchPattern":"if err := sl.Notify(n); err != nil && errors.Is(err, gsl.ErrNilChan) {\n    return fmt.Errorf(\"create the notification channel first: %w\", err)\n}","preventionTips":["Always make() the channel before registering notifications.","Unregister notifications before nil-ing channels in cleanup code.","Add nil-channel checks in test helpers that construct notification objects."],"tags":["nats","sublist","nil-channel","notification"],"backgroundTag":"nil-channel","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}