{"record":{"id":"f94dccd033042aac","repo":"tursodatabase/turso","slug":"only-finite-floating-point-values-can-be-bound","errorCode":null,"errorMessage":"only finite floating-point values can be bound","messagePattern":"only finite floating-point values can be bound","errorType":"validation","errorClass":"ToSqlConversionFailure","httpStatus":null,"severity":"error","filePath":"bindings/rust/src/batch.rs","lineNumber":60,"sourceCode":"impl BatchStatement {\n    /// Create a batch statement from SQL text and parameters, accepting the\n    /// same parameter forms as [`Connection::execute`](crate::Connection::execute).\n    pub fn new(sql: impl Into<String>, params: impl IntoParams) -> Result<Self> {\n        Ok(Self {\n            sql: sql.into(),\n            params: params.into_params()?,\n        })\n    }\n\n    pub(crate) fn validate_params(&self) -> Result<()> {\n        let has_infinity = match &self.params {\n            Params::None => false,\n            Params::Positional(values) => values.iter().any(is_infinite),\n            Params::Named(values) => values.iter().any(|(_, value)| is_infinite(value)),\n        };\n        if has_infinity {\n            return Err(Error::ToSqlConversionFailure(Box::new(\n                std::io::Error::new(\n                    std::io::ErrorKind::InvalidInput,\n                    \"only finite floating-point values can be bound\",\n                ),\n            )));\n        }\n        Ok(())\n    }\n\n    pub(crate) fn controls_transaction(&self) -> bool {\n        matches!(\n            first_sql_keyword(&self.sql).as_deref(),\n            Some(\"BEGIN\" | \"COMMIT\" | \"END\" | \"ROLLBACK\" | \"SAVEPOINT\" | \"RELEASE\")\n        )\n    }\n}\n\nfn is_infinite(value: &Value) -> bool {\n    matches!(value, Value::Real(number) if number.is_infinite())","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/bindings/rust/src/batch.rs#L42-L78","documentation":"The Rust batch API validates parameters before executing a batch and rejects any bound Value::Real that is NaN-adjacent infinity (f64::INFINITY or NEG_INFINITY). SQLite has no way to store IEEE infinity in its wire/file format, so binding one would silently corrupt or fail later; the library fails fast with ToSqlConversionFailure wrapping an InvalidInput io::Error.","triggerScenarios":"Calling BatchStatement::new with params containing an infinite f64 (e.g. computed via 1.0/0.0, f64::INFINITY, or overflowed arithmetic) in either positional or named Params, when the batch is later validated by validate_params during batch execution.","commonSituations":"Dividing by zero or accumulating overflow in Rust code that feeds values into a batch INSERT/UPDATE; deserializing JSON numbers like 1e999 into f64 infinity; log/metric aggregation producing inf and passing it straight to the database.","solutions":["Check parameter values with f64::is_finite() before constructing the BatchStatement and clamp, store NULL, or return an application error instead.","Use Option<f64> (Params None/Null) for values that may be infinite, mapping non-finite to NULL.","If infinity must be persisted, store a sentinel TEXT/REAL value (e.g. 'Infinity') and convert on read."],"exampleFix":"// before\nlet ratio = numerator / denominator; // may be inf\nconn.batch([BatchStatement::new(\"INSERT INTO t(v) VALUES (?1)\", (ratio,))?])?;\n// after\nlet ratio = if denominator != 0.0 { numerator / denominator } else { f64::NAN };\nlet v = if ratio.is_finite() { Some(ratio) } else { None };\nconn.batch([BatchStatement::new(\"INSERT INTO t(v) VALUES (?1)\", (v,))?])?;","handlingStrategy":"validation","validationCode":"fn ensure_bindable(params: &[f64]) -> Result<(), String> {\n    params.iter().find(|v| !v.is_finite())\n        .map_or(Ok(()), |v| Err(format!(\"non-finite param: {v}\")))\n}","typeGuard":"fn is_bindable_real(v: f64) -> bool { v.is_finite() }","tryCatchPattern":"match stmt_result {\n    Err(turso::Error::ToSqlConversionFailure(e)) if e.to_string().contains(\"finite\") => {\n        eprintln!(\"non-finite bind value: {e}\"); // sanitize params and retry\n    }\n    r => r.expect(\"batch failed\"),\n}","preventionTips":["Filter all float params with is_finite() before constructing statements","Map non-finite values to Option<f64> (NULL) at the data-model boundary","Guard divisions and accumulation that can overflow to infinity","Test numeric pipelines with extreme values (1e308*10, 0.0-divisions)"],"tags":["rust","parameter-binding","floating-point","validation"],"backgroundTag":"non-finite-float-bind","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-31T11:17:35.598Z","contentChangedAt":"2026-08-31T11:17:35.598Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}