dapr/dapr · error

Streaming unsupported!

Error message

Streaming unsupported!

What it means

FlushSSEResponse streams server-sent events by asserting the http.ResponseWriter implements http.Flusher; when it doesn't (a middleware wrapped the writer without forwarding Flush), it writes 500 'Streaming unsupported!' and returns nil — the error is deliberately swallowed, so callers see success while the client got a 500.

Source

Thrown at pkg/sse/sse.go:77

func HandleSSEGrpcResponse(res *invokev1.InvokeMethodResponse) error {
	if res == nil {
		return nil
	}

	statusOK := res.Status().GetCode() >= 200 && res.Status().GetCode() < 300
	msg := "no response received from stream"
	if statusOK {
		msg = "no expected response from stream"
	}

	return status.Errorf(codes.Internal, messages.ErrChannelInvoke, errors.New(msg))
}

func FlushSSEResponse(ctx context.Context, writer http.ResponseWriter, reader io.Reader) error {
	flusher, ok := writer.(http.Flusher)
	if !ok {
		http.Error(writer, "Streaming unsupported!", http.StatusInternalServerError)
		return nil
	}

	// Add defer close for streaming case
	closer, ok := reader.(io.Closer)
	if ok {
		defer closer.Close()
	}

	// Stream SSE data in real-time
	buf := make([]byte, 1024)
	for {
		if err := ctx.Err(); err != nil {
			return err
		}

		n, err := reader.Read(buf)
		if n > 0 {

View on GitHub (pinned to 74ad417027)

Solutions

  1. Make wrapper types implement Flush() by delegating to the underlying writer when it is an http.Flusher
  2. Move SSE routes outside the wrapping middleware chain
  3. In tests, decorate recorders with a Flush method or use writers that implement http.Flusher

Example fix

// before
type logWriter struct{ http.ResponseWriter }
// after
type logWriter struct {
	http.ResponseWriter
}

func (l logWriter) Flush() {
	if f, ok := l.ResponseWriter.(http.Flusher); ok {
		f.Flush()
	}
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Wire the SSE route only through writers that can flush.
func supportsFlush(w http.ResponseWriter) (http.Flusher, bool) {
	f, ok := w.(http.Flusher)
	return f, ok
}

Type guard

func canStreamSSE(w http.ResponseWriter) bool {
	_, ok := w.(http.Flusher)
	return ok
}

Try / catch

if f, ok := w.(http.Flusher); ok {
	f.Flush()
} else {
	// degrade: buffer the response instead of streaming, or 501 with a clear error
	http.Error(w, "streaming requires http.Flusher support", http.StatusNotImplemented)
}

Prevention

When it happens

Trigger: Invoking the SSE/grpc-proxy streaming path through a ResponseWriter wrapper (gzip, logging, metrics, custom auth middleware) whose concrete type lacks a Flush method; HTTP/1.0-style connections or test writers without flush support.

Common situations: Adding compression or observability middleware in front of handlers that wrap http.ResponseWriter and forget to delegate Flusher; unit tests using a custom recorder that does not implement Flush.

Related errors


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/b5c6cf6e58228f94. Report an issue: GitHub.