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
- Check the wrapped error type: 'no such host'/'connection refused' → fix network, proxy, or BaseURL.
- On 'context deadline exceeded', increase the timeout budget for the request.
- Verify connectivity with curl to the configured BaseURL.
- 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
- Wrap non-streaming calls in retry with exponential backoff
- Give large prompts generous context deadlines
- Check proxy/firewall rules for the Gemini API host
- Distinguish transport failures from ai.NewHTTPError before retrying
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
- stream API request failed: %w
- deadline exceeded
- stream API request failed: %w
- API request failed: %w
- API request failed: %w
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/422d227d0fdd9b89.
Report an issue: GitHub.