transact-rs/sqlx · error · io::Error (InvalidData)

extension entrypoint names passed to SQLite must not contain

Error message

extension entrypoint names passed to SQLite must not contain nul bytes

What it means

When loading a SQLite extension, sqlx converts the entrypoint name into a `CString` (a NUL-terminated C string) to pass to the SQLite C API. Rust strings may legally contain interior NUL bytes (`\0`), but C strings cannot, so `CString::new` fails. sqlx maps that failure to an `io::Error` of kind `InvalidData` rather than panicking.

Source

Thrown at sqlx-sqlite/src/connection/establish.rs:123

        }

        let filename = CString::new(filename).map_err(|_| {
            io::Error::new(
                io::ErrorKind::InvalidData,
                "filename passed to SQLite must not contain nul bytes",
            )
        })?;

        #[cfg(feature = "load-extension")]
        let extensions = options
            .extensions
            .iter()
            .map(|(name, entry)| {
                let entry = entry
                    .as_ref()
                    .map(|e| {
                        CString::new(e.as_bytes()).map_err(|_| {
                            io::Error::new(
                                io::ErrorKind::InvalidData,
                                "extension entrypoint names passed to SQLite must not contain nul bytes"
                            )
                        })
                    })
                    .transpose()?;
                Ok((
                    CString::new(name.as_bytes()).map_err(|_| {
                        io::Error::new(
                            io::ErrorKind::InvalidData,
                            "extension names passed to SQLite must not contain nul bytes",
                        )
                    })?,
                    entry,
                ))
            })
            .collect::<Result<IndexMap<CString, Option<CString>>, io::Error>>()?;

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Strip everything from the first NUL byte before passing the entrypoint: `entry.split('\0').next().unwrap_or("")`.
  2. Validate the string with `entry.contains('\0')` and return a clear application-level error before building `SqliteConnectOptions`.
  3. If the bytes come from a C API, use `CStr::from_bytes_until_nul` (or `CStr::from_ptr`) and convert with `to_string_lossy` instead of treating the raw buffer as a Rust `String`.

Example fix

// before
let entry = std::str::from_utf8(&buf).unwrap().to_string(); // may contain \0
opts = opts.extension(ext_name).with_argument(entry);

// after
let entry = std::str::from_utf8(&buf)?.split('\0').next().unwrap().to_string();
opts = opts.extension(ext_name).with_argument(entry);
Defensive patterns

Strategy: validation

Validate before calling

fn validate_entrypoint(entry: &str) -> Result<&str, String> {
    if entry.contains('\0') {
        Err(format!("extension entrypoint contains NUL byte: {:?}", entry))
    } else {
        Ok(entry)
    }
}
// let entry = validate_entrypoint(&raw_entry)?;

Type guard

fn is_cstring_safe(s: &str) -> bool {
    !s.as_bytes().contains(&b'\0')
}

Try / catch

match SqliteConnection::connect_with(&opts).await {
    Ok(conn) => conn,
    Err(e) if e.to_string().contains("must not contain nul bytes") => {
        // sanitize inputs and retry
        ...
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `SqliteConnectOptions::extension` / `SqliteConnectOptions::extension_argument` with an entrypoint string containing an interior `\0` byte (e.g. built from truncated buffers or C-side data), then connecting via `SqliteConnection::connect` / `AnyPool` which routes through `from_options` in establish.rs.

Common situations: Loading extension entrypoints read from binary sources, `String::from_utf8` of buffers that include NUL terminators, or dynamically constructed entrypoint names where a terminator was not stripped.

Related errors


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