googleapis/mcp-toolbox · error

failed to send request: %w

Error message

failed to send request: %w

What it means

This error wraps a low-level network/transport failure that occurred while the Looker Conversational Analytics tool was executing its HTTP request to the Google Cloud API via client.Do(req). It appears with the underlying error (e.g. DNS failure, TLS handshake error, context deadline exceeded) appended via %w, so the wrapped cause is always present in the message. The library throws it because the request never received an HTTP response at all — it is not about a bad status code.

Source

Thrown at internal/tools/looker/lookerconversationalanalytics/lookerconversationalanalytics.go:441

}

func getStream(ctx context.Context, client *http.Client, url string, payload CAPayload, headers map[string]string) ([]map[string]any, error) {
	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal payload: %w", err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(payloadBytes))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("API returned non-200 status: %d %s", resp.StatusCode, string(body))
	}

	var messages []map[string]any
	decoder := json.NewDecoder(resp.Body)

	// The response is a JSON array, so we read the opening bracket.
	if _, err := decoder.Token(); err != nil {
		if err == io.EOF {
			return nil, nil // Empty response is valid
		}
		return nil, fmt.Errorf("error reading start of json array: %w", err)
	}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Read the wrapped error after '%w' to identify the root cause (DNS vs TLS vs timeout).
  2. Verify outbound network connectivity to the Looker/API endpoint from the host running the toolbox.
  3. If the wrapped error is 'context deadline exceeded' or 'context canceled', increase the caller's timeout or check for premature cancellation upstream.
  4. Check proxy environment variables (HTTP_PROXY/HTTPS_PROXY/NO_PROXY) are correct.
  5. Retry the request, as some failures are transient.

Example fix

// before: context with no deadline control, fails on slow networks
ctx := r.Context()
resp, err := client.Do(req)
// after: give the request an explicit budget
ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
defer cancel()
req = req.WithContext(ctx)
resp, err := client.Do(req)
Defensive patterns

Strategy: retry

Validate before calling

// Go: preflight connectivity before invoking
func canReachEndpoint(ctx context.Context, url string) error {
    req, _ := http.NewRequestWithContext(ctx, http.MethodHead, url, nil)
    _, err := http.DefaultClient.Do(req)
    return err
}

Type guard

// Go: extract and classify the wrapped transport error
import ("errors"; "net"; "net/url"; "context")
func isNetworkErr(err error) bool {
    var dnsErr *net.DNSError
    var opErr *net.OpError
    return errors.As(err, &dnsErr) || errors.As(err, &opErr) || errors.Is(err, context.DeadlineExceeded)
}

Try / catch

err := invokeTool(ctx, req)
if err != nil && strings.Contains(err.Error(), "failed to send request") {
    if isNetworkErr(err) {
        // backoff-retry with jitter
        time.Sleep(backoff)
        err = invokeTool(ctx, req)
    }
    if err != nil { log.Printf("transport error: %v", err) }
}

Prevention

When it happens

Trigger: Any invocation of the looker-conversational-analytics tool where http.Client.Do fails: DNS resolution failure, connection refused/reset, TLS errors, or the request context being cancelled/timed out before a response arrives.

Common situations: No outbound network access or a proxy/firewall blocking googleapis.com; running in an environment with a short context timeout; misconfigured HTTPS_PROXY; IPv6/DNS issues in containers; transient network blips.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/f6feec981b44a6ed. Report an issue: GitHub.