googleapis/mcp-toolbox · error
error reading start of json array: %w
Error message
error reading start of json array: %w
What it means
getStream streams the response as a JSON array and first reads the opening delimiter token with decoder.Token(). If that fails with anything other than io.EOF (io.EOF is treated as a valid empty response), this error is returned — meaning the response body was not a parseable JSON array.
Source
Thrown at internal/tools/bigquery/bigqueryconversationalanalytics/bigqueryconversationalanalytics.go:303
return "", fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("API returned non-200 status: %d %s", resp.StatusCode, string(body))
}
var messages []map[string]any
decoder := json.NewDecoder(resp.Body)
dataMsgIdx := -1
// The response is a JSON array, so we read the opening bracket.
if _, err := decoder.Token(); err != nil {
if err == io.EOF {
return "", nil // Empty response is valid
}
return "", fmt.Errorf("error reading start of json array: %w", err)
}
for decoder.More() {
var rawMsg json.RawMessage
if err := decoder.Decode(&rawMsg); err != nil {
if err == io.EOF {
break
}
return "", fmt.Errorf("error decoding raw message: %w", err)
}
var msg map[string]any
if err := json.Unmarshal(rawMsg, &msg); err != nil {
return "", fmt.Errorf("error unmarshaling raw message: %w", err)
}
var processedMsg map[string]any
if dataResult := extractDataResult(msg); dataResult != nil {View on GitHub (pinned to 8cc6e09de2)
Solutions
- Log the raw response body to inspect what was actually returned (proxy HTML, truncated JSON, etc.).
- Check for proxies/gateways between the toolbox and the API that may rewrite or truncate responses.
- Retry the request — transient stream truncation often resolves on retry.
- If using a mock/test endpoint, make it return a JSON array of message objects.
Example fix
// before: mock returns an object
{"messages": []}
// after: mock must return an array like the real API
[{"systemMessage": {}}] Defensive patterns
Strategy: retry
Validate before calling
resp, err := client.Do(req)
if err != nil { return err }
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "json") {
return fmt.Errorf("unexpected content-type %q; proxy may be rewriting response", ct)
} Try / catch
result, err := tool.Invoke(ctx, params)
if err != nil && strings.Contains(err.Error(), "error reading start of json array") {
log.Printf("non-array response body; retrying: %v", err)
return retryRequest(req)
} Prevention
- Disable proxy/gateway response rewriting or buffering for this endpoint.
- Retry transient stream failures with backoff.
- Validate mock servers return a JSON array body.
When it happens
Trigger: Invoke on the tool when the GDA endpoint returns a 200 response whose body is not a JSON array — e.g. an HTML error page from a proxy/load balancer, a truncated response, or an unexpected JSON object shape.
Common situations: Intercepting proxies or API gateways rewriting the response; responses cut off mid-stream (network interruption after headers); testing against a mock server that returns a JSON object instead of an array.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- error decoding raw message: %w
- error unmarshaling raw message: %w
- error reading start of json array: %w
- error decoding stream message: %w
- error parsing JSON: %v
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/45804d4ac7205d18.
Report an issue: GitHub.