{"record":{"id":"0c95f377a73f057d","repo":"googleapis/mcp-toolbox","slug":"unable-to-parse-row-w-0c95f3","errorCode":null,"errorMessage":"unable to parse row: %w","messagePattern":"unable to parse row: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/mssql/mssql.go","lineNumber":136,"sourceCode":"\tdefer results.Close()\n\n\tcols, err := results.Columns()\n\t// If Columns() errors, it might be a DDL/DML without an OUTPUT clause.\n\t// We proceed, and results.Err() will catch actual query execution errors.\n\t// 'out' will remain an empty slice if cols is empty or err is not nil here.\n\tout := []any{}\n\tif err == nil && len(cols) > 0 {\n\t\t// create an array of values for each column, which can be re-used to scan each row\n\t\trawValues := make([]any, len(cols))\n\t\tvalues := make([]any, len(cols))\n\t\tfor i := range rawValues {\n\t\t\tvalues[i] = &rawValues[i]\n\t\t}\n\n\t\tfor results.Next() {\n\t\t\tscanErr := results.Scan(values...)\n\t\t\tif scanErr != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"unable to parse row: %w\", scanErr)\n\t\t\t}\n\t\t\trow := orderedmap.Row{}\n\t\t\tfor i, name := range cols {\n\t\t\t\trow.Add(name, rawValues[i])\n\t\t\t}\n\t\t\tout = append(out, row)\n\t\t}\n\t}\n\n\t// Check for errors from iterating over rows or from the query execution itself.\n\t// results.Close() is handled by defer.\n\tif err := results.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"errors encountered during query execution or row processing: %w\", err)\n\t}\n\n\treturn out, nil\n}\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/mssql/mssql.go#L118-L154","documentation":"This error occurs in `RunSQL` when `results.Scan(values...)` fails while iterating rows. The source scans each column into a `sql.RawBytes`, so scanning fails if the row shape doesn't match expectations — e.g. driver-level conversion problems or a NULL/encoding edge case the raw-bytes scan cannot handle.","triggerScenarios":"Calling RunSQL on a result set where Scan into []sql.RawBytes fails: driver conversion errors for unusual column types, column count changes mid-cursor, or a driver/dialect quirk with certain data types (e.g. some CLR/variant types).","commonSituations":"Querying columns with exotic types (hierarchyid, geometry, sql_variant) that the driver struggles to expose as raw bytes; schema changed between query and scan; driver version bugs with specific type mappings.","solutions":["Cast problematic columns in SQL (CAST(col AS NVARCHAR(MAX))) to friendly types","Unwrap the error to identify which column/type failed","Upgrade the go-mssqldb driver to the latest version","Avoid SELECT *; select only typed, well-defined columns"],"exampleFix":"// before\nstmt := \"SELECT geo FROM places\" // geometry column fails to scan\n// after\nstmt := \"SELECT CAST(geo AS NVARCHAR(MAX)) AS geo FROM places\"","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isScanErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"unable to parse row\")\n}","tryCatchPattern":"res, err := src.RunSQL(ctx, stmt, nil)\nif err != nil && strings.Contains(err.Error(), \"unable to parse row\") {\n    return fmt.Errorf(\"column type not scannable; CAST it in SQL: %w\", err)\n}","preventionTips":["CAST exotic types to strings/numbers in SELECT","Avoid SELECT * on tables with CLR/spatial columns","Keep go-mssqldb driver current","Test queries against production-shaped data"],"tags":["mssql","sql","scan","data-types"],"backgroundTag":"row-scan-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"}