{"record":{"id":"8a1ef7d0ca2e68df","repo":"googleapis/mcp-toolbox","slug":"api-returned-non-200-status-d-s-8a1ef7","errorCode":null,"errorMessage":"API returned non-200 status: %d %s","messagePattern":"API returned non-200 status: (.+?) (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/looker/lookerconversationalanalytics/lookerconversationalanalytics.go","lineNumber":447,"sourceCode":"\t}\n\n\treq, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(payloadBytes))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create request: %w\", err)\n\t}\n\tfor k, v := range headers {\n\t\treq.Header.Set(k, v)\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to send request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, _ := io.ReadAll(resp.Body)\n\t\treturn nil, fmt.Errorf(\"API returned non-200 status: %d %s\", resp.StatusCode, string(body))\n\t}\n\n\tvar messages []map[string]any\n\tdecoder := json.NewDecoder(resp.Body)\n\n\t// The response is a JSON array, so we read the opening bracket.\n\tif _, err := decoder.Token(); err != nil {\n\t\tif err == io.EOF {\n\t\t\treturn nil, nil // Empty response is valid\n\t\t}\n\t\treturn nil, fmt.Errorf(\"error reading start of json array: %w\", err)\n\t}\n\n\tfor decoder.More() {\n\t\tvar msg StreamMessage\n\t\tif err := decoder.Decode(&msg); err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/looker/lookerconversationalanalytics/lookerconversationalanalytics.go#L429-L465","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","solutions":["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.","Refresh or regenerate the OAuth token and confirm the required scopes for the Conversational Analytics API.","Verify the Looker project, model, and explore identifiers in the tool parameters.","Check Google Cloud status/quota if the body indicates rate limiting or internal errors."],"exampleFix":"// before: token missing required scope\nscope := \"https://www.googleapis.com/auth/cloud-platform.read-only\"\n// after: request the scope Conversational Analytics requires\nscope := \"https://www.googleapis.com/auth/cloud-platform\"","handlingStrategy":"validation","validationCode":"// Go: check token validity and scope before invoking\nfunc tokenLooksValid(tok string) bool {\n    return tok != \"\" && strings.HasPrefix(tok, \"ya29.\") || strings.Contains(tok, \".\") // opaque ID token check\n}\n// Prefer: call the tokeninfo endpoint\n// https://oauth2.googleapis.com/tokeninfo?access_token=... and verify exp + scopes","typeGuard":null,"tryCatchPattern":"err := invokeTool(ctx, req)\nif err != nil {\n    var status int\n    if n, _ := fmt.Sscanf(err.Error(), \"API returned non-200 status: %d\", &status); n == 1 {\n        switch {\n        case status == 401 || status == 403:\n            refreshCredentials(ctx) // re-auth with correct scopes/IAM\n        case status == 429 || status >= 500:\n            backoffRetry(ctx, req)\n        default:\n            log.Printf(\"request rejected (%d): fix parameters\", status)\n        }\n    }\n}","preventionTips":["Keep OAuth tokens refreshed and request cloud-platform (or the API's required) scopes.","Grant the service account the IAM roles Conversational Analytics needs.","Validate project/model/explore identifiers against the Looker instance before calls.","Add alerting on 429/5xx and honor Retry-After headers."],"tags":["http","api","looker","auth"],"backgroundTag":"api-non-200-status","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}