gofr-dev/gofr · error

stream value could not be encoded

Error message

stream value could not be encoded

What it means

errStreamCorrupt is returned by writeFrame in pkg/gofr/http/stream.go when a value pulled from the stream source cannot be encoded into a stream frame. The stream is aborted rather than sending a malformed or partial frame to the client.

Source

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

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)

	setStreamHeaders(r.w, s.Format)

View on GitHub (pinned to 187eb24962)

Solutions

  1. Make the streamed values encodable: use plain structs with exported fields and JSON-safe types
  2. Wrap or convert problematic values to encodable representations inside your Streamer before sending them on the channel
  3. Log the offending value to identify which item in the stream is corrupt
  4. Add a test streaming representative values end-to-end to catch encoding failures early

Example fix

// before
items <- func() {} // unencodable value -> errStreamCorrupt
// after
items <- map[string]string{"status": "ok"} // encodable value
Defensive patterns

Strategy: type-guard

Validate before calling

func encodable(v any) error {
    rv := reflect.ValueOf(v)
    switch rv.Kind() {
    case reflect.Chan, reflect.Func, reflect.UnsafePointer:
        return fmt.Errorf("value of type %T is not encodable", v)
    }
    return nil
}

Type guard

func isStreamCorrupt(err error) bool {
    return errors.Is(err, errStreamCorrupt)
}

Try / catch

err := streamValues(w, src)
if err != nil {
    if errors.Is(err, errStreamCorrupt) {
        log.Printf("dropping unencodable stream value: %v", err)
        return errStreamingAborted
    }
    return err
}

Prevention

When it happens

Trigger: A Streamer emits a value that the frame encoder cannot serialize (unsupported type, value containing channels/funcs/cyclic references) so writeFrame's encoding step fails and returns errStreamCorrupt.

Common situations: Streaming arbitrary Go values (e.g. structs with unexported fields the encoder rejects, or values that fail JSON-style marshaling); changing a streamed struct to include an unencodable field; emitting non-primitive types from a generic source.

Related errors


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