googleapis/mcp-toolbox · error

unable to scan row: %w

Error message

unable to scan row: %w

What it means

This error wraps a failure from rows.Scan() in the Oracle read path. RunSQL pre-allocates typed receivers (NullInt64, NullFloat64, NullTime, RawBytes, NullString) based on the reported Oracle column type; Scan fails when the driver cannot convert the wire value into the chosen receiver. Commonly this is a value whose actual type or size mismatches the column-type-based receiver choice.

Source

Thrown at internal/sources/oracle/oracle.go:206

				if _, scale, ok := colType.DecimalSize(); ok && scale == 0 {
					// Scale is 0, treat it as an integer.
					values[i] = new(sql.NullInt64)
				} else {
					// Scale is non-zero or unknown, treat
					// it as a float.
					values[i] = new(sql.NullFloat64)
				}
			case "DATE", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE":
				values[i] = new(sql.NullTime)
			case "JSON":
				values[i] = new(sql.RawBytes)
			default:
				values[i] = new(sql.NullString)
			}
		}

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

		vMap := make(map[string]any)
		for i, col := range cols {
			receiver := values[i]

			switch v := receiver.(type) {
			case *sql.NullInt64:
				if v.Valid {
					vMap[col] = v.Int64
				} else {
					vMap[col] = nil
				}
			case *sql.NullFloat64:
				if v.Valid {
					vMap[col] = v.Float64
				} else {
					vMap[col] = nil

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Read the wrapped %w driver error to identify which column and conversion failed.
  2. Check for NUMBER columns with scale 0 that exceed int64 range; cast them in SQL (e.g. TO_CHAR) or add a scale to force float handling.
  3. Ensure CLOB/BLOB columns are small enough or cast with DBMS_LOB.SUBSTR / TO_CHAR so they fit the string receiver.
  4. Upgrade or pin the godror/go-ora driver version, since DatabaseTypeName() output varies between driver versions.
  5. Verify session NLS/date formats if timestamps fail to scan; set explicit NLS settings or use TO_CHAR for date columns.

Example fix

// before
SELECT id, huge_number_col FROM t;

// after: avoid int64 overflow
SELECT id, TO_CHAR(huge_number_col) AS huge_number_col FROM t;
Defensive patterns

Strategy: validation

Validate before calling

rows, _ := db.Query("SELECT DATA_TYPE, DATA_PRECISION, DATA_SCALE FROM all_tab_columns WHERE table_name = :1 AND column_name = :2", tbl, col)
// reject NUMBER columns with scale 0 and precision > 18 before running the query

Try / catch

out, err := source.RunSQL(ctx, stmt, params, true)
if err != nil {
    var scanErr error
    if errors.As(err, &scanErr) && strings.Contains(err.Error(), "unable to scan row") {
        return fmt.Errorf("column type mismatch: cast problematic columns with TO_CHAR or TO_NUMBER in the query: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: RunSQL (readOnly=true) scanning a row where: a NUMBER value overflows int64 (scale 0 but huge, e.g. 99999999999999999999), a LOB/CLOB/BLOB column exceeds what the driver will scan into NullString, an INTERVAL or exotic type is returned but the driver's ColumnTypes() name didn't match any known case, or the driver returns nil in a way incompatible with the allocated receiver.

Common situations: Selecting very large NUMBER columns (e.g. sequence-generated IDs beyond int64 range); CLOB columns with go-ora returning sizes the driver refuses to convert; DATE/TIMESTAMP values the OCI driver cannot render into time.Time due to session NLS settings; driver version differences changing DatabaseTypeName() strings so the switch misroutes types.

Related errors


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