{"record":{"id":"71785a55114ad10a","repo":"wavetermdev/waveterm","slug":"sse-handler-is-nil-71785a","errorCode":null,"errorMessage":"sse handler is nil","messagePattern":"sse handler is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/openai/openai-backend.go","lineNumber":470,"sourceCode":"\t\t}\n\n\t\tif chatMsg.FunctionCall != nil && chatMsg.FunctionCall.CallId == callId {\n\t\t\tchatstore.DefaultChatStore.RemoveMessage(chatId, chatMsg.MessageId)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc RunOpenAIChatStep(\n\tctx context.Context,\n\tsse *sse.SSEHandlerCh,\n\tchatOpts uctypes.WaveChatOpts,\n\tcont *uctypes.WaveContinueResponse,\n) (*uctypes.WaveStopReason, []*OpenAIChatMessage, *uctypes.RateLimitInfo, error) {\n\tif sse == nil {\n\t\treturn nil, nil, nil, errors.New(\"sse handler is nil\")\n\t}\n\n\t// Get chat from store\n\tchat := chatstore.DefaultChatStore.Get(chatOpts.ChatId)\n\tif chat == nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"chat not found: %s\", chatOpts.ChatId)\n\t}\n\n\t// Validate that chatOpts.Config match the chat's stored configuration\n\tif chat.APIType != chatOpts.Config.APIType {\n\t\treturn nil, nil, nil, fmt.Errorf(\"API type mismatch: chat has %s, chatOpts has %s\", chat.APIType, chatOpts.Config.APIType)\n\t}\n\tif !uctypes.AreModelsCompatible(chat.APIType, chat.Model, chatOpts.Config.Model) {\n\t\treturn nil, nil, nil, fmt.Errorf(\"model mismatch: chat has %s, chatOpts has %s\", chat.Model, chatOpts.Config.Model)\n\t}\n\tif chat.APIVersion != chatOpts.Config.APIVersion {\n\t\treturn nil, nil, nil, fmt.Errorf(\"API version mismatch: chat has %s, chatOpts has %s\", chat.APIVersion, chatOpts.Config.APIVersion)\n\t}","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/openai/openai-backend.go#L452-L488","documentation":"RunOpenAIChatStep streams OpenAI responses through an sse.SSEHandlerCh and rejects a nil handler with 'sse handler is nil' at openai-backend.go:470. The handler is the sole delivery mechanism for streamed chunks, so the library fails fast rather than silently dropping output. Like the Gemini backend, this guards against caller initialization mistakes.","triggerScenarios":"RunOpenAIChatStep is invoked with sse == nil: the handler was never constructed by the caller, a nil pointer propagated from an earlier failure, or the handler was consumed/closed before this call in a reuse scenario.","commonSituations":"Custom integrations calling RunOpenAIChatStep directly; refactors that moved handler creation; nil returned from a factory function and passed through unchecked; concurrent use where one goroutine nils the shared handler.","solutions":["Construct the SSE handler before the call: sseHandler := sse.NewSSEHandlerCh(ctx)","Check any function that supplies the handler for a nil return and handle it before starting the chat step","Ensure the handler is created per-request rather than shared/closed across runs","Add a unit test asserting the handler is non-nil before RunOpenAIChatStep is invoked"],"exampleFix":"// before\nif handler == nil { /* nothing */ }\ngo RunOpenAIChatStep(ctx, handler, chatOpts, cont)\n// after\nif handler == nil {\n    handler = sse.NewSSEHandlerCh(ctx)\n}\ngo RunOpenAIChatStep(ctx, handler, chatOpts, cont)","handlingStrategy":"type-guard","validationCode":"if sse == nil {\n    sse = sse.NewSSEHandlerCh(ctx)\n}","typeGuard":"func hasSSEHandler(h *sse.SSEHandlerCh) bool { return h != nil }","tryCatchPattern":"if err != nil && err.Error() == \"sse handler is nil\" {\n    log.Error().Msg(\"OpenAI chat step invoked with nil SSE handler; check initialization order\")\n    return err\n}","preventionTips":["Construct the SSE handler before starting the chat step, not inside a later goroutine","Check any factory that returns a handler for nil before passing it on","Cover the handler-creation path with a unit test so refactors cannot silently break it"],"tags":["openai","sse","streaming","nil-pointer","programmer-error"],"backgroundTag":"nil-dependency","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}