transact-rs/sqlx · error · syn::Error

expected exactly 1 column, got {}

Error message

expected exactly 1 column, got {}

What it means

The `query_scalar!` family requires the query to return exactly one column, since its output type is a single value. `quote_query_scalar` checks the described result columns and fails at compile time if the count differs, including the actual count in the message.

Source

Thrown at sqlx-macros-core/src/query/output.rs:217

            #(#instantiations)*

            ::std::result::Result::Ok(#out_ty { #(#ident: #var_name),* })
        })
    }
}

pub fn quote_query_scalar<DB: DatabaseExt>(
    input: &QueryMacroInput,
    config: &Config,
    warnings: &mut Warnings,
    bind_args: &Ident,
    describe: &Describe<DB>,
) -> crate::Result<TokenStream> {
    let columns = describe.columns();

    if columns.len() != 1 {
        return Err(syn::Error::new(
            input.src_span,
            format!("expected exactly 1 column, got {}", columns.len()),
        )
        .into());
    }

    // attempt to parse a column override, otherwise fall back to the inferred type of the column
    let ty = if let Ok(rust_col) = column_to_rust(describe, config, warnings, 0) {
        rust_col.type_.to_token_stream()
    } else if input.checked {
        let ty = get_column_type::<DB>(config, warnings, 0, &columns[0]);
        if describe.nullable(0).unwrap_or(true) {
            quote! { ::std::option::Option<#ty> }
        } else {
            ty
        }
    } else {
        quote! { _ }

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Change the SQL to select exactly one column (e.g. `SELECT count(*) FROM ...`)
  2. If you need multiple values, use `query_as!` with a record struct instead
  3. If it uses a query file, fix the .sql file so it returns a single column

Example fix

// before
let names = query_scalar!("SELECT id, name FROM users").fetch_all(&pool).await?;
// after
let names = query_as!(User, "SELECT id, name FROM users").fetch_all(&pool).await?;
// or for one value:
let count: i64 = query_scalar!("SELECT count(*) FROM users").fetch_one(&pool).await?;
Defensive patterns

Strategy: validation

Validate before calling

// ensure the SQL returns exactly one column before using query_scalar!
// e.g. inspect the described query in a test:
let d = sqlx::describe("SELECT count(*) FROM users", &pool).await?;
assert_eq!(d.columns().len(), 1);

Prevention

When it happens

Trigger: Using `query_scalar!`/`query_scalar_unchecked!` with SQL that returns 0 or 2+ columns — e.g. `SELECT id, name FROM users` or a query that returns no columns.

Common situations: Converting `query_as!` code to `query_scalar!` without trimming the select list; editing the .sql file to add a column; migrations changing a view so it now returns extra columns.

Related errors


AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03). Data as JSON: /api/errors/9c63e26c7b2474bc. Report an issue: GitHub.