{"record":{"id":"a6744b7767a5d132","repo":"googleapis/mcp-toolbox","slug":"unable-to-execute-client-w-a6744b","errorCode":null,"errorMessage":"unable to execute client: %w","messagePattern":"unable to execute client: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/spanner/spanner.go","lineNumber":196,"sourceCode":"\t\tstmt.Params = params\n\t}\n\n\tif readOnly {\n\t\titer := s.SpannerClient().Single().Query(ctx, stmt)\n\t\tresults, opErr = processRows(iter)\n\t} else {\n\t\t_, opErr = s.SpannerClient().ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {\n\t\t\titer := txn.Query(ctx, stmt)\n\t\t\tresults, err = processRows(iter)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tif opErr != nil {\n\t\treturn nil, fmt.Errorf(\"unable to execute client: %w\", opErr)\n\t}\n\n\treturn results, nil\n}\n\nfunc initSpannerClient(ctx context.Context, tracer trace.Tracer, name, project, instance, dbname string) (*spanner.Client, error) {\n\t//nolint:all // Reassigned ctx\n\tctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name)\n\tdefer span.End()\n\n\t// Configure the connection to the database\n\tdb := fmt.Sprintf(\"projects/%s/instances/%s/databases/%s\", project, instance, dbname)\n\n\t// Create spanner client\n\tuserAgent, err := util.UserAgentFromContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/spanner/spanner.go#L178-L214","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := source.RunSQL(ctx, stmt, params)\nif err != nil {\n\tvar apiErr *googleapi.Error\n\tif errors.As(err, &apiErr) && (apiErr.Code == 409 || apiErr.Code == 503) {\n\t\t// retry with backoff (Aborted/Unavailable)\n\t}\n\treturn fmt.Errorf(\"spanner RunSQL failed: %w\", err)\n}","preventionTips":["Grant roles/spanner.databaseUser to the service account","Keep transactions short to minimize abort contention","Set realistic context deadlines for DDL/DML"],"tags":["spanner","transaction","sql-execution"],"backgroundTag":"database-query-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"}