SeaQL/sea-orm · error

Failed to get double

Error message

Failed to get double

What it means

Panic when sea-orm-sync's SQLite driver cannot decode a "REAL" column into f64 while building a ProxyRow. Because SQLite does not enforce storage types, a REAL-declared column may physically contain text or integer values (or NULL) that sqlx refuses to decode into the expected f64.

Source

Thrown at sea-orm-sync/src/driver/sqlx_sqlite.rs:427

            .iter()
            .map(|c| {
                (
                    c.name().to_string(),
                    match c.type_info().name() {
                        "BOOLEAN" => {
                            Value::Bool(row.try_get(c.ordinal()).expect("Failed to get boolean"))
                        }

                        "INTEGER" => {
                            Value::Int(row.try_get(c.ordinal()).expect("Failed to get integer"))
                        }

                        "BIGINT" | "INT8" => Value::BigInt(
                            row.try_get(c.ordinal()).expect("Failed to get big integer"),
                        ),

                        "REAL" => {
                            Value::Double(row.try_get(c.ordinal()).expect("Failed to get double"))
                        }

                        "TEXT" => Value::String(
                            row.try_get::<Option<String>, _>(c.ordinal())
                                .expect("Failed to get string")
                                .map(Box::new),
                        ),

                        "BLOB" => Value::Bytes(
                            row.try_get::<Option<Vec<u8>>, _>(c.ordinal())
                                .expect("Failed to get bytes")
                                .map(Box::new),
                        ),

                        #[cfg(feature = "with-chrono")]
                        "DATETIME" => {
                            use chrono::{DateTime, Utc};

View on GitHub (pinned to e29bcd1b41)

Solutions

  1. Normalize stored values: UPDATE t SET col = CAST(col AS REAL) WHERE typeof(col) != 'real'
  2. Decode as Option<f64> and treat NULL explicitly instead of non-Option try_get
  3. Enforce value hygiene at insert time by going through typed entity models rather than raw SQL
  4. Propagate the sqlx error with column name context instead of .expect

Example fix

// before
"REAL" => {
    Value::Double(row.try_get(c.ordinal()).expect("Failed to get double"))
}
// after
"REAL" => {
    Value::Double(row.try_get::<Option<f64>, _>(c.ordinal())
        .expect("Failed to get double")
        .unwrap_or(f64::NAN))  // or propagate with column context
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify REAL columns hold real storage class:
// SELECT typeof(col), count(*) FROM t GROUP BY typeof(col);

Type guard

fn is_real_storage(type_of: &str) -> bool { type_of == "real" }

Try / catch

let row = std::panic::catch_unwind(|| proxy_query(db)).unwrap_or_else(|_| fallback_row());

Prevention

When it happens

Trigger: Reading a REAL column whose stored value has a non-real storage class (TEXT like '3.14', INTEGER, or NULL decoded into non-Option f64).

Common situations: Floats inserted as quoted strings by another tool or ORM; data imported from CSV where numbers stayed text; NULLs in legacy rows; columns repurposed after schema changes.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of SeaQL/sea-orm@e29bcd1b41 (2026-09-10). Data as JSON: /api/errors/159c1fa2cc2a26ea. Report an issue: GitHub.