googleapis/mcp-toolbox · error

API returned non-200 status: %d %s

Error message

API returned non-200 status: %d %s

What it means

The Conversational Analytics API call completed at the transport level but returned an HTTP status other than 200; the tool surfaces the status code and the raw response body so the cause is visible. This library treats only 200 as success — redirects, 4xx auth/validation failures and 5xx server errors all land here. The body text usually contains the Google API error explanation.

Source

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

	}

	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)
	}

	for decoder.More() {
		var msg StreamMessage
		if err := decoder.Decode(&msg); err != nil {
			if err == io.EOF {
				break

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the status code and body in the message: 401/403 → fix credentials/IAM, 400/404 → fix request parameters (project, model, explore names), 429/5xx → back off and retry.
  2. Refresh or regenerate the OAuth token and confirm the required scopes for the Conversational Analytics API.
  3. Verify the Looker project, model, and explore identifiers in the tool parameters.
  4. Check Google Cloud status/quota if the body indicates rate limiting or internal errors.

Example fix

// before: token missing required scope
scope := "https://www.googleapis.com/auth/cloud-platform.read-only"
// after: request the scope Conversational Analytics requires
scope := "https://www.googleapis.com/auth/cloud-platform"
Defensive patterns

Strategy: validation

Validate before calling

// Go: check token validity and scope before invoking
func tokenLooksValid(tok string) bool {
    return tok != "" && strings.HasPrefix(tok, "ya29.") || strings.Contains(tok, ".") // opaque ID token check
}
// Prefer: call the tokeninfo endpoint
// https://oauth2.googleapis.com/tokeninfo?access_token=... and verify exp + scopes

Try / catch

err := invokeTool(ctx, req)
if err != nil {
    var status int
    if n, _ := fmt.Sscanf(err.Error(), "API returned non-200 status: %d", &status); n == 1 {
        switch {
        case status == 401 || status == 403:
            refreshCredentials(ctx) // re-auth with correct scopes/IAM
        case status == 429 || status >= 500:
            backoffRetry(ctx, req)
        default:
            log.Printf("request rejected (%d): fix parameters", status)
        }
    }
}

Prevention

When it happens

Trigger: Calling the tool with an invalid or expired OAuth access token (401), insufficient IAM permissions on the Looker instance (403), a malformed request payload such as a bad project/instance or model reference (400/404), or a Google-side server error (500/503).

Common situations: Expired or wrongly-scoped service account credentials; user lacking Conversational Analytics API permissions; wrong Looker instance URL or project ID in config; Google API outage or quota exhaustion (429).

Related errors


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