micro/go-micro · error

stream API request failed: %w

Error message

stream API request failed: %w

What it means

Stream's HTTP POST to the Gemini streaming endpoint failed at the transport layer: DNS failure, connection refused, TLS error, timeout, or context cancellation. No HTTP response was received, so this is a network-level problem, not an API error status. The wrapped %w error carries the net/http detail.

Source

Thrown at ai/gemini/gemini.go:196

	reqBody, err := json.Marshal(apiReq)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal stream request: %w", err)
	}

	apiURL := strings.TrimRight(p.opts.BaseURL, "/") +
		"/v1beta/models/" + p.opts.Model + ":streamGenerateContent?alt=sse"
	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))
	if err != nil {
		return nil, fmt.Errorf("failed to create stream request: %w", err)
	}
	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("Accept", "text/event-stream")
	httpReq.Header.Set("x-goog-api-key", p.opts.APIKey)

	httpResp, err := http.DefaultClient.Do(httpReq)
	if err != nil {
		return nil, fmt.Errorf("stream API request failed: %w", err)
	}
	if httpResp.StatusCode != http.StatusOK {
		defer httpResp.Body.Close()
		respBody, _ := io.ReadAll(httpResp.Body)
		return nil, ai.NewHTTPError(httpResp, respBody)
	}
	return &streamReader{body: httpResp.Body, scanner: bufio.NewScanner(httpResp.Body)}, nil
}

type streamReader struct {
	body    io.ReadCloser
	scanner *bufio.Scanner
	closed  bool
}

func (s *streamReader) Recv() (*ai.Response, error) {
	for s.scanner.Scan() {
		line := strings.TrimSpace(s.scanner.Text())

View on GitHub (pinned to 24529f1404)

Solutions

  1. Read the wrapped error: 'connection refused'/'no such host' means reachability — check network, proxy, and BaseURL.
  2. If it says 'context deadline exceeded', increase the request timeout or check upstream cancellation.
  3. Verify outbound HTTPS access to the Gemini endpoint (curl the BaseURL).
  4. Configure HTTP_PROXY/HTTPS_PROXY correctly or bypass the proxy for this host.
  5. Wrap the call in bounded retry with backoff for transient network failures.

Example fix

// before
stream, err := provider.Stream(ctx, req)
// after
var netErr net.Error
stream, err := provider.Stream(ctx, req)
if errors.As(err, &netErr) && netErr.Timeout() {
    ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    defer cancel()
    stream, err = provider.Stream(ctx, req)
}
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", host+":443", 3*time.Second)
if err != nil {
    return fmt.Errorf("gemini endpoint unreachable: %w", err)
}
conn.Close()

Type guard

func isTransientNetworkErr(err error) bool {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() { return true }
    var de *net.DNSError
    return errors.As(err, &de) ||
        strings.Contains(err.Error(), "connection refused") ||
        errors.Is(err, context.Canceled) == false && strings.Contains(err.Error(), "EOF")
}

Try / catch

var stream *ai.Stream
err := retry.Do(3, 2*time.Second, func() error {
    var e error
    stream, e = provider.Stream(ctx, req)
    if e != nil && strings.Contains(e.Error(), "stream API request failed") {
        return e // retryable transport failure
    }
    return retry.Stop(e)
})

Prevention

When it happens

Trigger: http.DefaultClient.Do returned err while posting to :streamGenerateContent — unreachable host, proxy issues, TLS interception, canceled context mid-flight, or network outage.

Common situations: See trigger scenarios.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/181e7ab35860b316. Report an issue: GitHub.