{"record":{"id":"f6af9e355ac6e290","repo":"googleapis/mcp-toolbox","slug":"unable-to-iterate-through-query-results-w","errorCode":null,"errorMessage":"unable to iterate through query results: %w","messagePattern":"unable to iterate through query results: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/bigquery/bigquery.go","lineNumber":643,"sourceCode":"\t// column names to values, and return the collection of rows.\n\tjob, err := query.Run(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to execute query: %w\", err)\n\t}\n\tit, err := job.Read(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to read query results: %w\", err)\n\t}\n\n\tout := []any{}\n\tfor s.MaxQueryResultRows <= 0 || len(out) < s.MaxQueryResultRows {\n\t\tvar val []bigqueryapi.Value\n\t\terr = it.Next(&val)\n\t\tif err == iterator.Done {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to iterate through query results: %w\", err)\n\t\t}\n\t\tschema := it.Schema\n\t\trow := orderedmap.Row{}\n\t\tfor i, field := range schema {\n\t\t\trow.Add(field.Name, NormalizeValue(val[i]))\n\t\t}\n\t\tout = append(out, row)\n\t}\n\t// If the query returned any rows, return them directly.\n\tif len(out) > 0 {\n\t\treturn out, nil\n\t}\n\n\t// This handles the standard case for a SELECT query that successfully\n\t// executes but returns zero rows.\n\tif statementType == \"SELECT\" {\n\t\treturn \"The query returned 0 rows.\", nil\n\t}","sourceCodeStart":625,"sourceCodeEnd":661,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/bigquery/bigquery.go#L625-L661","documentation":"This error wraps any failure returned by the BigQuery row iterator's Next() call while paging through a query's result rows. The library throws it because a successful query job can still fail during row streaming — the initial job completion does not guarantee every page of rows can be fetched. The original iterator error (including context.DeadlineExceeded, transport failures, or page-level BigQuery API errors) is preserved via %w so callers can inspect it with errors.Is/errors.As.","triggerScenarios":"Calling Invoke on a BigQuery tool whose query returns rows, and it.Next(&val) (bigquery.RowIterator.Next) returns a non-nil error other than iterator.Done — e.g. a transient HTTP/transport failure while fetching the next page, a context deadline exceeded mid-iteration, or a page-level BigQuery API error (5xx, rate limit) while reading results.","commonSituations":"Long-running queries streamed over a slow network; context timeouts during result pagination; BigQuery backend transient errors or 429 rate-limit responses on the tabledata/list pages; stopped or expired jobs; cancelled requests when the caller's context times out.","solutions":["Retry the operation (the query itself, not just the iteration) if the wrapped error is transient (net errors, 5xx, 429) — BigQuery iterators are not resumable mid-stream.","Increase the request's context deadline / timeout so slow result streams can complete.","Check the wrapped error with errors.As to see if it's a googleapi.Error and inspect its code for quota or permission issues.","Reduce result size (LIMIT, paging) to shorten the streaming window and lower the chance of mid-iteration failures."],"exampleFix":"// before\nfor {\n  var val []bigqueryapi.Value\n  err = it.Next(&val)\n  if err == iterator.Done { break }\n  if err != nil { return nil, fmt.Errorf(\"unable to iterate through query results: %w\", err) }\n}\n// after\nfor {\n  var val []bigqueryapi.Value\n  ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n  defer cancel()\n  itPager.PageInfo().MaxSize = 10000 // fetch larger pages, fewer round-trips\n  err = it.Next(&val)\n  if errors.Is(err, iterator.Done) { break }\n  if err != nil {\n    if isRetryable(err) { /* retry query */ }\n    return nil, fmt.Errorf(\"unable to iterate through query results: %w\", err)\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Go\nrows, err := tool.Invoke(ctx, params)\nif err != nil {\n  if strings.Contains(err.Error(), \"unable to iterate through query results\") {\n    var gerr *googleapi.Error\n    if errors.As(err, &gerr) && (gerr.Code == 429 || gerr.Code >= 500) {\n      // retry the whole query after backoff; iterators are not resumable\n    }\n    if errors.Is(err, context.DeadlineExceeded) {\n      // re-invoke with a longer deadline\n    }\n  }\n}","preventionTips":["Set generous context timeouts for queries expected to return many rows.","Use LIMIT/pagination to keep result streams short.","Retry the entire query on transient (5xx/429) failures instead of resuming iteration.","Monitor for rate-limit errors and add backoff."],"tags":["bigquery","pagination","network","error-wrapping"],"backgroundTag":"iterator-paging-failed","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"}