transact-rs/sqlx · error
Cannot use both try from and json nullable
Error message
Cannot use both try from and json nullable
What it means
A compile-time panic in sqlx's `#[derive(FromRow)]` macro (expand_derive_from_row_struct). A field marked `#[sqlx(try_from = "T")]` was also marked with a nullable json attribute (`#[sqlx(json(nullable))]` or `#[sqlx(json)]` with nullability). try_from conversion and JSON deserialization are mutually exclusive generation strategies, so the macro aborts compilation with this panic.
Source
Thrown at sqlx-macros-core/src/derives/row.rs:180
parse_quote!(
__row.try_get::<::sqlx::types::Json<_>, _>(#id_s)
.and_then(|v| {
<#ty as ::std::convert::TryFrom::<#try_from>>::try_from(v.0)
.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),
}
})
})
)
},
// Try from + Json nullable
(false, Some(_), Some(JsonAttribute::Nullable)) => {
panic!("Cannot use both try from and json nullable")
},
// Json
(false, None, Some(JsonAttribute::NonNullable)) => {
predicates
.push(parse_quote!(::sqlx::types::Json<#ty>: ::sqlx::decode::Decode<#lifetime, R::Database>));
predicates.push(parse_quote!(::sqlx::types::Json<#ty>: ::sqlx::types::Type<R::Database>));
parse_quote!(__row.try_get::<::sqlx::types::Json<_>, _>(#id_s).map(|x| x.0))
},
(false, None, Some(JsonAttribute::Nullable)) => {
predicates
.push(parse_quote!(::core::option::Option<::sqlx::types::Json<#ty>>: ::sqlx::decode::Decode<#lifetime, R::Database>));
predicates.push(parse_quote!(::core::option::Option<::sqlx::types::Json<#ty>>: ::sqlx::types::Type<R::Database>));
parse_quote!(__row.try_get::<::core::option::Option<::sqlx::types::Json<_>>, _>(#id_s).map(|x| x.and_then(|y| y.0)))
},
};
View on GitHub (pinned to 03af8bcc57)
Solutions
- Drop the `json(nullable)` attribute and keep `try_from` if the column is a plain (possibly nullable) SQL value convertible via TryFrom.
- Drop `try_from` and keep `#[sqlx(json)]` if the column truly stores JSON; handle nullability with `Option<T>` as the field type.
- Split into two fields or use a custom FromRow implementation if both conversion steps are genuinely needed.
Example fix
// before
#[derive(sqlx::FromRow)]
struct Row {
#[sqlx(try_from = "String")]
#[sqlx(json(nullable))]
payload: Payload,
}
// after (json only, Option for nullability)
#[derive(sqlx::FromRow)]
struct Row {
#[sqlx(json)]
payload: Option<Payload>,
} Defensive patterns
Strategy: validation
Validate before calling
// Detect conflicting try_from + json attributes before building rg -n '#\[sqlx\(try_from' -A2 src/ | rg '#\[sqlx\(json'
Prevention
- Use Option<T> field types for nullability instead of json(nullable) combined with try_from
- Keep try_from for scalar conversions and json for JSON columns, never both
- Review derive attribute diffs when refactoring struct fields
When it happens
Trigger: Deriving FromRow with a field like `#[sqlx(try_from = "i64")] #[sqlx(json(nullable))] value: Value`. Any macro expansion for that struct (query_as!, FromRow derive) hits the `(false, Some(_), Some(JsonAttribute::Nullable))` match arm and panics.
Common situations: Combining a numeric try_from conversion with a nullable JSON column after a schema change; merging attribute sets when refactoring field types; following outdated examples that mix the two attributes.
Related errors
- Cannot use both flatten and json
- 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/929f471e06f87630.
Report an issue: GitHub.