googleapis/mcp-toolbox · error

unable to parse row: %w

Error message

unable to parse row: %w

What it means

Wraps rows.Scan failures while iterating result rows in RunSQL. Scan fails when a column value cannot be converted into the *interface{} destination — usually a driver-level type (e.g. Firebird BLOB subtype, numeric/decimal, timestamp with unusual precision) the firebirdsql driver returns in a form database/sql rejects.

Source

Thrown at internal/sources/firebird/firebird.go:127

	defer rows.Close()

	cols, err := rows.Columns()
	if err != nil {
		return nil, fmt.Errorf("unable to get columns: %w", err)
	}

	values := make([]any, len(cols))
	scanArgs := make([]any, len(values))
	for i := range values {
		scanArgs[i] = &values[i]
	}

	out := []any{}
	for rows.Next() {

		err = rows.Scan(scanArgs...)
		if err != nil {
			return nil, fmt.Errorf("unable to parse row: %w", err)
		}

		vMap := make(map[string]any)
		for i, col := range cols {
			if b, ok := values[i].([]byte); ok {
				vMap[col] = string(b)
			} else {
				vMap[col] = values[i]
			}
		}
		out = append(out, vMap)
	}

	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("error iterating rows: %w", err)
	}

	// In most cases, DML/DDL statements like INSERT, UPDATE, CREATE, etc. might return no rows

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Cast problematic columns in SQL (e.g. CAST(blob_col AS VARCHAR(...)) or SUBSTRING) instead of selecting raw BLOB/ARRAY columns
  2. Upgrade the firebirdsql driver to the latest version for scan fixes
  3. Set a compatible connection charset (e.g. UTF8) in the DSN
  4. Narrow the SELECT list to plain scalar columns

Example fix

// before
err = rows.Scan(scanArgs...)
if err != nil {
    return nil, fmt.Errorf("unable to parse row: %w", err)
}
// after
err = rows.Scan(scanArgs...)
if err != nil {
    return nil, fmt.Errorf("unable to parse row %d: %w", len(out), err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Avoid raw BLOB/ARRAY columns in the SELECT list
for _, col := range problematicTypes {
    if strings.Contains(strings.ToUpper(statement), col) {
        return fmt.Errorf("cast %s to VARCHAR in SQL to avoid scan errors", col)
    }
}

Type guard

func isScanTypeError(err error) bool {
    return strings.Contains(err.Error(), "unsupported Scan") || strings.Contains(err.Error(), "converting")
}

Try / catch

err = rows.Scan(scanArgs...)
if err != nil {
    if isScanTypeError(err) {
        return nil, fmt.Errorf("unsupported column type at row %d; CAST the column in SQL: %w", len(out), err)
    }
    return nil, fmt.Errorf("unable to parse row %d: %w", len(out), err)
}

Prevention

When it happens

Trigger: RunSQL hits a row containing a column type the driver cannot scan into any (e.g. malformed BLOB/ARRAY columns, oversized DECIMAL, NULL handling bug in the driver, or charset decoding failure).

Common situations: SELECT * on tables with BLOB or array columns; Firebird dialect 1 legacy column types; non-UTF8 character-set databases producing undecodable strings; driver version bugs with TIMESTAMP/TIME types.

Understand the failure class

Related errors


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