{"record":{"id":"edfcd16971ea44ac","repo":"transact-rs/sqlx","slug":"filename-passed-to-sqlite-must-not-contain-nul-byt","errorCode":null,"errorMessage":"filename passed to SQLite must not contain nul bytes","messagePattern":"filename passed to SQLite must not contain nul bytes","errorType":"exception","errorClass":"io::Error (InvalidData)","httpStatus":null,"severity":"error","filePath":"sqlx-sqlite/src/connection/establish.rs","lineNumber":108,"sourceCode":"        if let Some(vfs) = options.vfs.as_deref() {\n            query_params.insert(\"vfs\", vfs);\n        }\n\n        if !query_params.is_empty() {\n            filename = format!(\n                \"file:{}?\",\n                percent_encoding::percent_encode(filename.as_bytes(), NON_ALPHANUMERIC),\n            );\n\n            // Suffix serializer automatically handles `&` separators for us.\n            let filename_len = filename.len();\n            filename = form_urlencoded::Serializer::for_suffix(filename, filename_len)\n                .extend_pairs(query_params)\n                .finish();\n        }\n\n        let filename = CString::new(filename).map_err(|_| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"filename passed to SQLite must not contain nul bytes\",\n            )\n        })?;\n\n        #[cfg(feature = \"load-extension\")]\n        let extensions = options\n            .extensions\n            .iter()\n            .map(|(name, entry)| {\n                let entry = entry\n                    .as_ref()\n                    .map(|e| {\n                        CString::new(e.as_bytes()).map_err(|_| {\n                            io::Error::new(\n                                io::ErrorKind::InvalidData,\n                                \"extension entrypoint names passed to SQLite must not contain nul bytes\"\n                            )","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-sqlite/src/connection/establish.rs#L90-L126","documentation":"After appending query parameters, from_options converts the filename string into a CString for the SQLite C API. CString::new fails if the string embeds an interior NUL byte, so sqlx maps that failure to this InvalidData error. An embedded nul in the filename would truncate the path at the C boundary, so sqlx refuses it.","triggerScenarios":"Connecting to SQLite with a SqliteConnectOptions whose filename (or a query-param value appended to it, e.g. mode/cache options derived from user input) contains a '\\0' character, producing CString::new failure.","commonSituations":"Paths or options read from binary input, log files, or user forms containing literal NUL characters; truncated C-string data copied into a Rust String; malicious or corrupt configuration values.","solutions":["Sanitize/validate the filename before building options: reject or strip any '\\0' characters","Trim the value at the first NUL if the trailing content is known garbage (filename.split('\\0').next())","Fix the source of the path (config file, env var, DB row) that embedded the nul byte","Add an input-validation error upstream so users get a clearer message than the connection failure"],"exampleFix":"// before\nlet opts = SqliteConnectOptions::new().filename(raw_name); // raw_name may contain '\\0'\nlet pool = SqlitePool::connect_with(opts).await?;\n// after\nlet clean = raw_name.split('\\0').next().context(\"filename contained nul byte\")?;\nlet pool = SqlitePool::connect(&format!(\"sqlite://{clean}\")).await?;","handlingStrategy":"validation","validationCode":"fn ensure_no_nul(s: &str) -> Result<&str, String> {\n    if s.contains('\\0') {\n        Err(format!(\"SQLite filename contains nul byte: {:?}\", s))\n    } else {\n        Ok(s)\n    }\n}\nlet filename = ensure_no_nul(&raw_name)?;\nlet opts = SqliteConnectOptions::new().filename(filename);","typeGuard":"fn is_nul_free(s: &str) -> bool {\n    !s.as_bytes().contains(&b'\\0')\n}","tryCatchPattern":"match SqlitePool::connect_with(opts).await {\n    Ok(pool) => Ok(pool),\n    Err(e) if e.to_string().contains(\"must not contain nul bytes\") => {\n        Err(anyhow!(\"database path contains a nul byte; check the configuration source\"))\n    }\n    Err(e) => Err(e.into()),\n}","preventionTips":["Reject '\\0' in any filename or option value sourced from user or binary input","Truncate at first NUL only when trailing data is known garbage","Sanitize config values read from binary formats, logs, or databases before connecting"],"tags":["sqlite","validation","connection","nul-byte"],"backgroundTag":"invalid-utf8-path","analyzedSha":"03af8bcc5711a1935580a54bea249c219a0c217d","analyzedAt":"2026-09-03T15:01:28.752Z","contentChangedAt":"2026-09-03T15:01:28.752Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}