transact-rs/sqlx · error

Cannot use both flatten and json

Error message

Cannot use both flatten and json

What it means

This is a compile-time panic inside sqlx's `#[derive(FromRow)]` proc macro (expand_derive_from_row_struct). A struct field was annotated with both `#[sqlx(flatten)]` and `#[sqlx(json)]`, which are mutually exclusive codegen strategies: flatten spreads another FromRow type's columns, while json deserializes the column as JSON into the field type. The macro cannot generate code for both, so it deliberately panics to fail the build.

Source

Thrown at sqlx-macros-core/src/derives/row.rs:134

                    predicates.push(parse_quote!(#try_from: ::sqlx::FromRow<#lifetime, R>));
                    parse_quote!(
                        <#try_from as ::sqlx::FromRow<#lifetime, R>>::from_row(__row)
                            .and_then(|v| {
                                <#ty as ::std::convert::TryFrom::<#try_from>>::try_from(v)
                                    .map_err(|e| {
                                        // Triggers a lint warning if `TryFrom::Err = Infallible`
                                        #[allow(unreachable_code)]
                                        ::sqlx::Error::ColumnDecode {
                                            index: #id_s.to_string(),
                                            source: sqlx::__spec_error!(e),
                                        }
                                    })
                            })
                    )
                }
                // Flatten + Json
                (true, _, Some(_)) => {
                    panic!("Cannot use both flatten and json")
                }
                // Try from
                (false, Some(try_from), None) => {
                    predicates
                        .push(parse_quote!(#try_from: ::sqlx::decode::Decode<#lifetime, R::Database>));
                    predicates.push(parse_quote!(#try_from: ::sqlx::types::Type<R::Database>)); 

                    parse_quote!(
                        __row.try_get(#id_s)
                            .and_then(|v| {
                                <#ty as ::std::convert::TryFrom::<#try_from>>::try_from(v)
                                    .map_err(|e| {
                                        // Triggers a lint warning if `TryFrom::Err = Infallible`
                                        #[allow(unreachable_code)]
                                        ::sqlx::Error::ColumnDecode {
                                            index: #id_s.to_string(),
                                            source: sqlx::__spec_error!(e),
                                        }

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Remove `#[sqlx(flatten)]` from the field if you want it deserialized from a single JSON column (keep `#[sqlx(json)]`).
  2. Remove `#[sqlx(json)]` from the field if you want its columns merged via FromRow flatten (keep `#[sqlx(flatten)]`).
  3. If you need both behaviors, split the data into two fields: one flattened struct field and one `#[sqlx(json)]` field.

Example fix

// before
#[derive(sqlx::FromRow)]
struct Row {
    #[sqlx(flatten)]
    #[sqlx(json)]
    meta: Meta,
}

// after (keep json only)
#[derive(sqlx::FromRow)]
struct Row {
    #[sqlx(json)]
    meta: Meta,
}
Defensive patterns

Strategy: validation

Validate before calling

// Compile-time: verify no field carries both attributes
cargo check 2>&1 | grep -F 'Cannot use both flatten and json'
// In code review, grep derives:
// rg -n '#\[sqlx\(flatten\)\]' -A1 | rg '#\[sqlx\(json'

Prevention

When it happens

Trigger: Deriving FromRow on a struct where a single field carries both attributes, e.g. `#[sqlx(flatten)] #[sqlx(json)] pub meta: Meta`. Any call to `query_as!`, `query_as::<_, T>`, or `FromRow::from_row` for that struct triggers macro expansion and the panic.

Common situations: Refactoring a struct where one field was flattened and another was json-typed, and the attributes get copied onto the same field; merging two structs with conflicting field annotations; copy-pasting attribute lines from another field.

Related errors


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