jmoiron/sqlx · error

non-struct dest type %s with >1 columns (%d)

Error message

non-struct dest type %s with >1 columns (%d)

What it means

In scanAll's row-preparation path, if the destination's base type is scannable (primitive or sql.Scanner) but the result set has more than one column, sqlx cannot map several columns onto one value and errors with the destination kind and column count.

Source

Thrown at sqlx.go:934

	}
	direct.SetLen(0)

	isPtr := slice.Elem().Kind() == reflect.Ptr
	base := reflectx.Deref(slice.Elem())
	scannable := isScannable(base)

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

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

	// if it's a base type make sure it only has 1 column;  if not return an error
	if scannable && len(columns) > 1 {
		return fmt.Errorf("non-struct dest type %s with >1 columns (%d)", base.Kind(), len(columns))
	}

	if !scannable {
		var values []interface{}
		var m *reflectx.Mapper

		switch rows := rows.(type) {
		case *Rows:
			m = rows.Mapper
		default:
			m = mapper()
		}

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

View on GitHub (pinned to 41dac167fd)

Solutions

  1. Restrict the SELECT list to a single column.
  2. Change the destination to a slice of structs and use StructScan semantics.
  3. Alias/restructure the query so only the needed value is returned.

Example fix

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

// after
var ids []int
db.Select(&ids, "SELECT id FROM users")
Defensive patterns

Strategy: validation

Validate before calling

cols, err := q.Columns()
if err != nil { return err }
if isScannable(dest) && len(cols) > 1 {
    return fmt.Errorf("scalar dest needs 1 column, query returns %d", len(cols))
}

Type guard

func singleColumnOK(dest interface{}, cols []string) bool {
    t := reflectx.Deref(reflect.TypeOf(dest))
    isStruct := t.Kind() == reflect.Struct && !reflect.PtrTo(t).Implements(reflect.TypeOf((*sql.Scanner)(nil)).Elem())
    return isStruct || len(cols) == 1
}

Try / catch

if err := db.Select(&vals, q); err != nil {
    if strings.Contains(err.Error(), "non-struct dest type") {
        return fmt.Errorf("query must return one column for %T: %w", vals, err)
    }
    return err
}

Prevention

When it happens

Trigger: Get/Select (scanAll) with a non-struct dest (e.g. []string, *int) while the query returns len(columns) > 1.

Common situations: Selecting extra columns (id plus value) into a slice of primitives; leftover SELECT * statements paired with scalar destinations.

Related errors


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