Skip to content

sqlite: decoding NULL into non-Option targets silently yields empty/zero values instead of erroring #4191

@meng-xu-cs

Description

@meng-xu-cs

I have found these related issues/pull requests

This is a follow-up to #3221 (which is now closed) rather than a different root cause.

Issue #3221 showed the bool case (NULL -> false). This report broadens the scope: the same SQLite decode behavior also affects String, Vec<u8>, i64, and f64, and the text/blob path appears to conflate SQL NULL with legitimate zero-length TEXT/BLOB values.

Description

When decoding SQLite rows into non-Option Rust types, SQL NULL is silently converted into default-looking values instead of returning a decode error.

Confirmed examples:

  • String -> ""
  • Vec<u8> -> []
  • i64 -> 0
  • f64 -> 0.0
  • bool -> false

Option<T> still behaves as expected (NULL -> None), so the difference is silent and easy to miss.

This also affects higher-level APIs like query_as() / FromRow, since they go through the same row decode path.

Reproduction steps

use sqlx::{Connection, Row};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut conn = sqlx::SqliteConnection::connect("sqlite::memory:").await?;

    let row = sqlx::query(
        "SELECT CAST(NULL AS TEXT)    AS t,
                CAST(NULL AS BLOB)    AS b,
                CAST(NULL AS INTEGER) AS i,
                CAST(NULL AS REAL)    AS f,
                CAST(NULL AS INTEGER) AS bo"
    )
    .fetch_one(&mut conn)
    .await?;

    println!("String={:?}", row.try_get::<String, _>("t"));
    println!("Vec<u8>={:?}", row.try_get::<Vec<u8>, _>("b"));
    println!("i64={:?}", row.try_get::<i64, _>("i"));
    println!("f64={:?}", row.try_get::<f64, _>("f"));
    println!("bool={:?}", row.try_get::<bool, _>("bo"));
    println!("Option<String>={:?}", row.try_get::<Option<String>, _>("t"));

    Ok(())
}

This will output

String=Ok("")
Vec<u8>=Ok([])
i64=Ok(0)
f64=Ok(0.0)
bool=Ok(false)
Option<String>=Ok(None)

SQLx version

main branch

Enabled SQLx features

default features

Database server and version

SQLite

Operating system

MacOS

Rust version

1.94.0 (4a4ef493e 2026-03-02)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions