{"record":{"id":"170c8d4631d1834c","repo":"googleapis/mcp-toolbox","slug":"unable-to-get-column-types-w-170c8d","errorCode":null,"errorMessage":"unable to get column types: %w","messagePattern":"unable to get column types: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/cloudsqlmysql/cloud_sql_mysql.go","lineNumber":155,"sourceCode":"\t\treturn nil, fmt.Errorf(\"unable to execute query: %w\", err)\n\t}\n\tdefer results.Close()\n\n\tcols, err := results.Columns()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to retrieve rows column name: %w\", err)\n\t}\n\n\t// create an array of values for each column, which can be re-used to scan each row\n\trawValues := make([]any, len(cols))\n\tvalues := make([]any, len(cols))\n\tfor i := range rawValues {\n\t\tvalues[i] = &rawValues[i]\n\t}\n\n\tcolTypes, err := results.ColumnTypes()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to get column types: %w\", err)\n\t}\n\n\tout := []any{}\n\tfor results.Next() {\n\t\terr := results.Scan(values...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to parse row: %w\", err)\n\t\t}\n\t\trow := orderedmap.Row{}\n\t\tfor i, name := range cols {\n\t\t\tval := rawValues[i]\n\t\t\tif val == nil {\n\t\t\t\trow.Add(name, nil)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconvertedValue, err := mysqlcommon.ConvertToType(colTypes[i], val)\n\t\t\tif err != nil {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/cloudsqlmysql/cloud_sql_mysql.go#L137-L173","documentation":"This error wraps a failure from results.ColumnTypes() in RunSQL. ColumnTypes() fetches detailed type information for each column; an error here indicates the driver lost access to the result metadata, typically because the connection or result set became invalid right after Columns() succeeded.","triggerScenarios":"Calling RunSQL when the MySQL connection is interrupted between the Columns() call and ColumnTypes(), or the driver fails to parse/return column type descriptors for the result set.","commonSituations":"Server failover or connection kill mid-metadata-fetch, transient network errors, driver bugs with exotic column types or collations, extremely wide result sets over flaky links.","solutions":["Retry the query — this is nearly always transient between two adjacent driver calls.","Keep pooled connections healthy (SetConnMaxLifetime, ping-before-use) so the connection is not reaped mid-request.","Check Cloud SQL instance health/logs for restarts or failovers coinciding with the error.","Narrow result sets (fewer/wider types) if driver type parsing is implicated; upgrade the mysql driver if a known bug matches.","Verify network path stability as with other mid-query connection drops."],"exampleFix":"// before\npool.SetMaxOpenConns(10)\n// after\npool.SetMaxOpenConns(10)\npool.SetConnMaxLifetime(5 * time.Minute)\nctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()","handlingStrategy":"retry","validationCode":"func ensureHealthyPool(db *sql.DB) error {\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n    if err := db.PingContext(ctx); err != nil {\n        return fmt.Errorf(\"pool unhealthy before query: %w\", err)\n    }\n    return nil\n}","typeGuard":"func isTransientConnectionLoss(err error) bool {\n    msg := err.Error()\n    return strings.Contains(msg, \"broken pipe\") ||\n        strings.Contains(msg, \"bad connection\") ||\n        strings.Contains(msg, \"connection reset\") ||\n        errors.Is(err, io.EOF) ||\n        errors.Is(err, context.Canceled)\n}","tryCatchPattern":"var result any\nvar err error\nfor attempt := 0; attempt < 2; attempt++ {\n    result, err = src.RunSQL(ctx, statement, params)\n    if err == nil {\n        break\n    }\n    if !strings.Contains(err.Error(), \"column types\") || !isTransientConnectionLoss(err) {\n        break\n    }\n    time.Sleep(200 * time.Millisecond)\n}","preventionTips":["Bound connection lifetime (SetConnMaxLifetime) to outlive server-side wait_timeout kills.","Wrap RunSQL calls in a small retry-with-backoff for transient mid-query failures.","Watch instance logs for failovers that coincide with metadata-fetch errors.","Select narrower result sets and upgrade the mysql driver if specific column types repeatedly trigger it.","Keep network paths (proxy/VPC connector) monitored for resets."],"tags":["mysql","resultset","metadata","cloudsql"],"backgroundTag":"stale-database-connection","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"}