googleapis/mcp-toolbox · error

errors encountered during row iteration: %w

Error message

errors encountered during row iteration: %w

What it means

TiDB RunSQL wraps any error returned by the *sql.Rows cursor after iterating all rows (results.Err()). During iteration the driver may hit network drops, context cancellation, or protocol errors that only surface via Err() once rows are exhausted. The toolbox wraps it so the underlying driver error is preserved via %w.

Source

Thrown at internal/sources/tidb/tidb.go:180

				if err := json.Unmarshal(byteVal, &unmarshaledData); err != nil {
					return nil, fmt.Errorf("unable to unmarshal json data %s", val)
				}
				vMap[name] = unmarshaledData
			case "TEXT", "VARCHAR", "NVARCHAR":
				byteVal, ok := val.([]byte)
				if !ok {
					return nil, fmt.Errorf("expected []byte for text-like column, but got %T", val)
				}
				vMap[name] = string(byteVal)
			default:
				vMap[name] = val
			}
		}
		out = append(out, vMap)
	}

	if err := results.Err(); err != nil {
		return nil, fmt.Errorf("errors encountered during row iteration: %w", err)
	}

	return out, nil
}

func IsTiDBCloudHost(host string) bool {
	pattern := `gateway\d{2}\.(.+)\.(prod|dev|staging)\.(.+)\.tidbcloud\.com`
	match, err := regexp.MatchString(pattern, host)
	if err != nil {
		return false
	}
	return match
}

func initTiDBConnectionPool(ctx context.Context, tracer trace.Tracer, name, host, port, user, pass, dbname string, useSSL bool) (*sql.DB, error) {
	//nolint:all // Reassigned ctx
	ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name)
	defer span.End()

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Check the wrapped driver error for context cancellation/deadline and retry with a longer context timeout
  2. Verify network stability between the client and TiDB (proxies, LBs, VPC peering) and connection max-lifetime settings
  3. Reduce result set size (LIMIT, pagination) or raise TiDB query memory/timeout limits
  4. Confirm TLS/connectivity to TiDB Cloud (port 4000, correct host) and driver version

Example fix

// before
results, err := pool.QueryContext(ctx, statement, params...)
// after
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
defer cancel()
results, err := pool.QueryContext(ctx, statement, params...)
Defensive patterns

Strategy: retry

Validate before calling

// ensure context has enough headroom before running
if deadline, ok := ctx.Deadline(); !ok || time.Until(deadline) < 30*time.Second {
    var cancel context.CancelFunc
    ctx, cancel = context.WithTimeout(ctx, 5*time.Minute)
    defer cancel()
}

Try / catch

out, err := src.RunSQL(ctx, stmt, params)
if err != nil && strings.Contains(err.Error(), "errors encountered during row iteration") {
    if errors.Is(err, context.DeadlineExceeded) || isTransientNetErr(err) {
        out, err = retryWithBackoff(3, func() (any, error) { return src.RunSQL(ctx, stmt, params) })
    }
}

Prevention

When it happens

Trigger: Calling Source.RunSQL on a TiDB source where the underlying mysql driver connection breaks mid-result-set: network interruption, server-side query kill/timeout, context cancellation, or packet corruption while streaming rows.

Common situations: Long-running SELECTs on TiDB Cloud hitting query timeouts; idle connection dropped by a proxy/load balancer between rows; client context cancelled while a large result set is still streaming.

Related errors


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