{"record":{"id":"7cb6e97a6b35c1e3","repo":"wavetermdev/waveterm","slug":"sse-handler-is-nil-7cb6e9","errorCode":null,"errorMessage":"sse handler is nil","messagePattern":"sse handler is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/gemini/gemini-backend.go","lineNumber":187,"sourceCode":"\t\treturn nil, err\n\t}\n\n\t// Set headers\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"x-goog-api-key\", opts.APIToken)\n\n\treturn req, nil\n}\n\n// RunGeminiChatStep executes a chat step using the Gemini API\nfunc RunGeminiChatStep(\n\tctx context.Context,\n\tsseHandler *sse.SSEHandlerCh,\n\tchatOpts uctypes.WaveChatOpts,\n\tcont *uctypes.WaveContinueResponse,\n) (*uctypes.WaveStopReason, *GeminiChatMessage, *uctypes.RateLimitInfo, error) {\n\tif sseHandler == 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 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\n\t// Context with timeout if provided\n\tif chatOpts.Config.TimeoutMs > 0 {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/gemini/gemini-backend.go#L169-L205","documentation":"RunGeminiChatStep streams Gemini responses through an SSE handler channel. It rejects a nil *sse.SSEHandlerCh at the top of the function because without a handler there is nowhere to deliver streaming events. This is a programmer-error guard: the caller must construct the SSE handler before starting the chat step.","triggerScenarios":"RunGeminiChatStep is called with sseHandler == nil — e.g. a caller forgot to create sse.NewSSEHandlerCh, a refactor reordered initialization so the handler is created after the chat step starts, or a nil handler was passed through from an error path.","commonSituations":"Wiring a new backend integration and skipping handler setup; concurrency bug where the handler variable is still nil when the goroutine launches; tests calling RunGeminiChatStep directly without a handler stub.","solutions":["Create the SSE handler before calling RunGeminiChatStep: handler := sse.NewSSEHandlerCh(...)","Trace why the handler variable is nil at call time (initialization order, error path, or copy of a nil pointer)","If the handler creation itself failed, abort the chat step instead of proceeding with nil","In tests, provide a real or mocked SSEHandlerCh rather than nil"],"exampleFix":"// before\nvar sseHandler *sse.SSEHandlerCh\ngo RunGeminiChatStep(ctx, sseHandler, chatOpts, cont)\n// after\nsseHandler := sse.NewSSEHandlerCh(ctx)\ngo RunGeminiChatStep(ctx, sseHandler, chatOpts, cont)","handlingStrategy":"type-guard","validationCode":"if sseHandler == nil {\n    return fmt.Errorf(\"cannot run Gemini chat step: SSE handler not initialized\")\n}","typeGuard":"func handlerReady(h *sse.SSEHandlerCh) bool { return h != nil }","tryCatchPattern":"if err != nil && err.Error() == \"sse handler is nil\" {\n    return fmt.Errorf(\"internal wiring bug: chat step started without an SSE handler\")\n}","preventionTips":["Always create the SSE handler immediately before launching the chat step goroutine","Never share or reuse handlers across chat steps; create one per request","Add an assertion/test that the handler is non-nil at every RunGeminiChatStep call site"],"tags":["gemini","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"}