micro/go-micro · error

API request failed: %w

Error message

API request failed: %w

What it means

callAPI's HTTP POST to the Gemini generateContent endpoint failed at the transport layer before any response arrived — DNS, connection, TLS, or timeout/context cancellation. This is a network-level failure, distinct from HTTP error statuses, which the library reports via ai.NewHTTPError instead.

Source

Thrown at ai/gemini/gemini.go:303

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

	apiURL := strings.TrimRight(p.opts.BaseURL, "/") +
		"/v1beta/models/" + p.opts.Model + ":generateContent"

	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, apiURL, bytes.NewReader(reqBody))
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create request: %w", err)
	}

	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("x-goog-api-key", p.opts.APIKey)

	httpResp, err := http.DefaultClient.Do(httpReq)
	if err != nil {
		return nil, nil, fmt.Errorf("API request failed: %w", err)
	}
	defer httpResp.Body.Close()

	respBody, _ := io.ReadAll(httpResp.Body)
	if httpResp.StatusCode != http.StatusOK {
		return nil, nil, ai.NewHTTPError(httpResp, respBody)
	}

	var geminiResp struct {
		Candidates []struct {
			Content struct {
				Parts []struct {
					Text         string          `json:"text"`
					FunctionCall *functionCallPB `json:"functionCall"`
				} `json:"parts"`
			} `json:"content"`
		} `json:"candidates"`
	}

View on GitHub (pinned to 24529f1404)

Solutions

  1. Check the wrapped error type: 'no such host'/'connection refused' → fix network, proxy, or BaseURL.
  2. On 'context deadline exceeded', increase the timeout budget for the request.
  3. Verify connectivity with curl to the configured BaseURL.
  4. Add retry-with-backoff around the call for transient network faults.

Example fix

// before
resp, err := provider.Generate(ctx, req)
if err != nil { return err }
// after
resp, err := provider.Generate(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "context deadline exceeded") {
        ctx2, cancel := context.WithTimeout(context.Background(), 120*time.Second)
        defer cancel()
        resp, err = provider.Generate(ctx2, req)
    }
    if err != nil { return err }
}
Defensive patterns

Strategy: retry

Validate before calling

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

Type guard

func isTransportFailure(err error) bool {
    if err == nil { return false }
    var ne net.Error
    if errors.As(err, &ne) { return true }
    var de *net.DNSError
    return errors.As(err, &de) || strings.Contains(err.Error(), "API request failed")
}

Try / catch

resp, err := provider.Generate(ctx, req)
if err != nil && isTransportFailure(err) {
    for attempt := 0; attempt < 3; attempt++ {
        time.Sleep(time.Duration(1<<attempt) * time.Second)
        resp, err = provider.Generate(ctx, req)
        if err == nil || !isTransportFailure(err) { break }
    }
}

Prevention

When it happens

Trigger: http.DefaultClient.Do returned a non-nil error while calling :generateContent — unreachable host, refused connection, TLS failure, proxy error, or canceled/deadline-exceeded context.

Common situations: No internet or DNS outage; firewall/proxy blocking generativelanguage.googleapis.com; wrong BaseURL host; overly tight context deadline on large prompts.

Related errors


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