googleapis/mcp-toolbox · error
unable to execute client: %w
Error message
unable to execute client: %w
What it means
RunSQL (internal/sources/spanner/spanner.go:196) executes statements through spanner client ReadWriteTransaction. The transaction callback collects errors into opErr; if the transaction (including commit/retry attempts) fails, the error is wrapped as "unable to execute client". This is a generic wrapper over any Spanner transaction failure.
Source
Thrown at internal/sources/spanner/spanner.go:196
stmt.Params = params
}
if readOnly {
iter := s.SpannerClient().Single().Query(ctx, stmt)
results, opErr = processRows(iter)
} else {
_, opErr = s.SpannerClient().ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
iter := txn.Query(ctx, stmt)
results, err = processRows(iter)
if err != nil {
return err
}
return nil
})
}
if opErr != nil {
return nil, fmt.Errorf("unable to execute client: %w", opErr)
}
return results, nil
}
func initSpannerClient(ctx context.Context, tracer trace.Tracer, name, project, instance, dbname string) (*spanner.Client, error) {
//nolint:all // Reassigned ctx
ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name)
defer span.End()
// Configure the connection to the database
db := fmt.Sprintf("projects/%s/instances/%s/databases/%s", project, instance, dbname)
// Create spanner client
userAgent, err := util.UserAgentFromContext(ctx)
if err != nil {
return nil, err
}View on GitHub (pinned to 8cc6e09de2)
Solutions
- Unwrap the %w chain and read the underlying Spanner error code (e.g. googleapi.Error) to identify the real cause
- Verify the service account has roles/spanner.databaseUser on the instance
- Test the statement directly in the Spanner console to rule out syntax errors
- Retry on codes Aborted/Unavailable — the client retries internally but may still exhaust
- Check context deadlines if the statement is long-running
Defensive patterns
Strategy: retry
Try / catch
err := source.RunSQL(ctx, stmt, params)
if err != nil {
var apiErr *googleapi.Error
if errors.As(err, &apiErr) && (apiErr.Code == 409 || apiErr.Code == 503) {
// retry with backoff (Aborted/Unavailable)
}
return fmt.Errorf("spanner RunSQL failed: %w", err)
} Prevention
- Grant roles/spanner.databaseUser to the service account
- Keep transactions short to minimize abort contention
- Set realistic context deadlines for DDL/DML
When it happens
Trigger: Running a DML/DDL statement via RunSQL where the transaction fails: Spanner server error, dead aborted transaction exhausted retries, permission denied, statement syntax error, or context cancellation mid-transaction.
Common situations: IAM role lacking spanner.database user privileges; malformed SQL statement; transient aborts during high contention; Spanner instance paused or deleted; network issues between client and Spanner.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- column 'object_details' is not a string, but %T
- unable to unmarshal JSON: %w
- unable to create new client: %w
- unable to execute query: %w
- description is required for tool %q
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/a6744b7767a5d132.
Report an issue: GitHub.