jmoiron/sqlx · error

scannable dest type %s with >1 columns (%d) in result

Error message

scannable dest type %s with >1 columns (%d) in result

What it means

When scanning into a non-struct, "scannable" destination (a type implementing sql.Scanner or a primitive like string/int), sqlx requires the result set to contain exactly one column. If the query returns more than one column, ScanInto/StructScan cannot sensibly map multiple columns onto a single value, so it errors with the column count.

Source

Thrown at sqlx.go:771

	}
	if v.IsNil() {
		return errors.New("nil pointer passed to StructScan destination")
	}

	base := reflectx.Deref(v.Type())
	scannable := isScannable(base)

	if structOnly && scannable {
		return structOnlyError(base)
	}

	columns, err := r.Columns()
	if err != nil {
		return err
	}

	if scannable && len(columns) > 1 {
		return fmt.Errorf("scannable dest type %s with >1 columns (%d) in result", base.Kind(), len(columns))
	}

	if scannable {
		return r.Scan(dest)
	}

	m := r.Mapper

	fields := m.TraversalsByName(v.Type(), columns)
	// if we are not unsafe and are missing fields, return an error
	if f, err := missingFields(fields); err != nil && !r.unsafe {
		return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
	}
	values := make([]interface{}, len(columns))

	err = fieldsByTraversal(v, fields, values, true)
	if err != nil {
		return err

View on GitHub (pinned to 41dac167fd)

Solutions

  1. Change the query to select exactly one column (e.g. SELECT name FROM ...).
  2. Switch the destination to a struct so multiple columns can be mapped to fields.
  3. Use sqlx.Rows.Columns()/StructScan manually if you truly need multi-column raw scanning.

Example fix

// before
var names []string
db.Select(&names, "SELECT id, name FROM users")

// after
var names []string
db.Select(&names, "SELECT name FROM users")
Defensive patterns

Strategy: validation

Validate before calling

cols, err := rows.Columns()
if err != nil { return err }
if len(cols) != 1 { return fmt.Errorf("need exactly 1 column, got %d", len(cols)) }

Type guard

func isScannableSingle(dest interface{}) bool {
    t := reflectx.Deref(reflect.TypeOf(dest))
    return t.Kind() != reflect.Struct || reflect.PtrTo(t).Implements(_scannerInterface)
}

Try / catch

if err := db.Select(&names, q); err != nil {
    if strings.Contains(err.Error(), "scannable dest type") {
        // fall back to struct destination
    }
    return err
}

Prevention

When it happens

Trigger: rows.ScanScan / ScanInto(dest) where dest's base kind is scannable (primitive or sql.Scanner implementor) and r.Columns() returns len(columns) > 1.

Common situations: Scanning into a []string or sql.Scanner struct while the query selects two or more columns (e.g. SELECT id, name ...); accidentally leaving SELECT * when the dest is a slice of primitives.

Related errors


AI-assisted analysis of jmoiron/sqlx@41dac167fd (2026-09-03). Data as JSON: /api/errors/94a9d4d23ab490ec. Report an issue: GitHub.