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
- Remove `#[sqlx(flatten)]` from the field if you want it deserialized from a single JSON column (keep `#[sqlx(json)]`).
- Remove `#[sqlx(json)]` from the field if you want its columns merged via FromRow flatten (keep `#[sqlx(flatten)]`).
- 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
- Allow only one sqlx field attribute per field by team convention
- Document that flatten and json are mutually exclusive in your ORM guidelines
- Run cargo check in CI so the macro panic surfaces on the first build
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
- Cannot use both try from and json nullable
- absolute paths will only work on the current machine
- paths relative to the current file's directory are not curre
- failed to read query file at {}: {}
- expected exactly 1 column, got {}
AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03).
Data as JSON: /api/errors/7472b90b88d037d3.
Report an issue: GitHub.