gofr-dev/gofr · error

stream source is nil

Error message

stream source is nil

What it means

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.

Source

Thrown at pkg/gofr/http/stream.go:20

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"time"

	resTypes "gofr.dev/pkg/gofr/http/response"
)

const (
	defaultHeartbeat  = 15 * time.Second
	streamWriteWindow = 30 * time.Second
)

var (
	errStreamPanic   = errors.New("stream source panicked")
	errNilStream     = errors.New("stream source is nil")
	errStreamCorrupt = errors.New("stream value could not be encoded")
)

// handleStream drains s.Source to the client, flushing after every write. It pulls values on
// demand so a slow client throttles the producer, sends a periodic keep-alive so a dropped client
// is detected while idle, bounds each write with a deadline, and always closes the source — leaving
// no goroutine behind when the client disconnects mid-stream. A Source that also honors its own
// context cancels promptly even without a heartbeat.
func (r Responder) handleStream(s resTypes.Stream) {
	if s.Source == nil {
		r.w.WriteHeader(http.StatusInternalServerError)
		_, _ = r.w.Write([]byte(`{"error":{"message":"` + errNilStream.Error() + `"}}` + "\n"))

		return
	}

	rc := http.NewResponseController(r.w)

View on GitHub (pinned to 187eb24962)

Solutions

  1. Ensure the code path that builds the Streamer always returns a valid implementation
  2. Check and handle the error from your source factory before handing the source to the stream
  3. Treat typed-nil pointers (e.g. (*mySource)(nil)) as invalid and return a real error instead
  4. Add a unit test asserting the stream setup fails fast when the source is absent

Example fix

// before
src, _ := NewSource(cfg)
handleStream(src) // src may be nil -> errNilStream
// after
src, err := NewSource(cfg)
if err != nil {
    return err
}
if src == nil {
    return errors.New("no stream source configured")
}
handleStream(src)
Defensive patterns

Strategy: validation

Validate before calling

func ensureSource(src resTypes.Streamer) error {
    if src == nil {
        return errors.New("stream source is nil")
    }
    return nil
}

Type guard

func isNilStreamer(v any) bool {
    if v == nil { return true }
    rv := reflect.ValueOf(v)
    switch rv.Kind() {
    case reflect.Ptr, reflect.Interface, reflect.Func:
        return rv.IsNil()
    }
    return false
}

Try / catch

if err := startStream(src); err != nil {
    if errors.Is(err, errNilStream) {
        log.Printf("no stream source configured: %v", err)
        return ErrNoSource
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/d8e94d80e1e21b4f. Report an issue: GitHub.