{"record":{"id":"d8e94d80e1e21b4f","repo":"gofr-dev/gofr","slug":"stream-source-is-nil","errorCode":null,"errorMessage":"stream source is nil","messagePattern":"stream source is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/http/stream.go","lineNumber":20,"sourceCode":"\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\tresTypes \"gofr.dev/pkg/gofr/http/response\"\n)\n\nconst (\n\tdefaultHeartbeat  = 15 * time.Second\n\tstreamWriteWindow = 30 * time.Second\n)\n\nvar (\n\terrStreamPanic   = errors.New(\"stream source panicked\")\n\terrNilStream     = errors.New(\"stream source is nil\")\n\terrStreamCorrupt = errors.New(\"stream value could not be encoded\")\n)\n\n// handleStream drains s.Source to the client, flushing after every write. It pulls values on\n// demand so a slow client throttles the producer, sends a periodic keep-alive so a dropped client\n// is detected while idle, bounds each write with a deadline, and always closes the source — leaving\n// no goroutine behind when the client disconnects mid-stream. A Source that also honors its own\n// context cancels promptly even without a heartbeat.\nfunc (r Responder) handleStream(s resTypes.Stream) {\n\tif s.Source == nil {\n\t\tr.w.WriteHeader(http.StatusInternalServerError)\n\t\t_, _ = r.w.Write([]byte(`{\"error\":{\"message\":\"` + errNilStream.Error() + `\"}}` + \"\\n\"))\n\n\t\treturn\n\t}\n\n\trc := http.NewResponseController(r.w)\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/http/stream.go#L2-L38","documentation":"errNilStream is declared in pkg/gofr/http/stream.go and indicates the Streamer source supplied to the streaming endpoint is nil. The framework cannot drain a nil source, so it refuses to start the stream rather than panicking later.","triggerScenarios":"Passing a nil Streamer (or a typed-nil pointer) as the source when setting up a streaming response, so handleStream/readStream detect there is nothing to drain.","commonSituations":"Constructing a stream source conditionally and leaving the nil case unhandled; a factory function returning nil on error whose error is ignored; JSON/config-driven source selection defaulting to nil.","solutions":["Ensure the code path that builds the Streamer always returns a valid implementation","Check and handle the error from your source factory before handing the source to the stream","Treat typed-nil pointers (e.g. (*mySource)(nil)) as invalid and return a real error instead","Add a unit test asserting the stream setup fails fast when the source is absent"],"exampleFix":"// before\nsrc, _ := NewSource(cfg)\nhandleStream(src) // src may be nil -> errNilStream\n// after\nsrc, err := NewSource(cfg)\nif err != nil {\n    return err\n}\nif src == nil {\n    return errors.New(\"no stream source configured\")\n}\nhandleStream(src)","handlingStrategy":"validation","validationCode":"func ensureSource(src resTypes.Streamer) error {\n    if src == nil {\n        return errors.New(\"stream source is nil\")\n    }\n    return nil\n}","typeGuard":"func isNilStreamer(v any) bool {\n    if v == nil { return true }\n    rv := reflect.ValueOf(v)\n    switch rv.Kind() {\n    case reflect.Ptr, reflect.Interface, reflect.Func:\n        return rv.IsNil()\n    }\n    return false\n}","tryCatchPattern":"if err := startStream(src); err != nil {\n    if errors.Is(err, errNilStream) {\n        log.Printf(\"no stream source configured: %v\", err)\n        return ErrNoSource\n    }\n    return err\n}","preventionTips":["Always check the error from source constructors before use","Avoid typed-nil returns (return nil, err not &T{}, err)","Default-fill source configuration instead of leaving it unset","Unit-test stream setup paths where config is missing"],"tags":["streaming","nil-check"],"backgroundTag":"nil-stream-source","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}