{"record":{"id":"39a9955da4c1b10b","repo":"tursodatabase/turso","slug":"message-e","errorCode":null,"errorMessage":"{message}: {e}","messagePattern":"\\{message\\}: \\{e\\}","errorType":"exception","errorClass":"napi::Error","httpStatus":null,"severity":"error","filePath":"bindings/javascript/src/lib.rs","lineNumber":233,"sourceCode":"            // make the JS step loop spin without letting the backoff expire.\n            let sleep_ms = duration.as_millis().clamp(1, u32::MAX as u128) as u32;\n            Ok((STEP_SLEEP, sleep_ms))\n        }\n        Ok(turso_core::StepResult::Done) => Ok((STEP_DONE, 0)),\n        Ok(turso_core::StepResult::Interrupt) => {\n            Err(create_generic_error(\"statement was interrupted\"))\n        }\n        Ok(turso_core::StepResult::Busy) => Err(create_generic_error(\"database is locked\")),\n        Err(e) => Err(to_generic_error(\"step failed\", e)),\n    }\n}\n\nfn to_generic_error<E: std::error::Error>(message: &str, e: E) -> napi::Error {\n    Error::new(Status::GenericFailure, format!(\"{message}: {e}\"))\n}\n\nfn to_error<E: std::error::Error>(status: napi::Status, message: &str, e: E) -> napi::Error {\n    Error::new(status, format!(\"{message}: {e}\"))\n}\n\nfn create_generic_error(message: &str) -> napi::Error {\n    Error::new(Status::GenericFailure, message)\n}\n\nfn create_error(status: napi::Status, message: &str) -> napi::Error {\n    Error::new(status, message)\n}\n\nfn query_timeout_duration(timeout_ms: u32) -> Option<std::time::Duration> {\n    if timeout_ms > 0 {\n        Some(std::time::Duration::from_millis(timeout_ms as u64))\n    } else {\n        None\n    }\n}\n","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/javascript/src/lib.rs#L215-L251","documentation":"Generic napi error formatter in the JS binding: to_error(status, message, e) renders any Rust std::error::Error as \"{message}: {e}\" under a caller-chosen napi status. Unlike to_generic_error it is used where the call site picks a specific status; the message prefix still identifies which binding operation failed.","triggerScenarios":"Any napi entry point that maps a native error with a non-generic status - argument conversion or open/prepare failures inside the JS wrapper - producing messages like \"<operation>: <Rust error string>\".","commonSituations":"Passing wrong argument types or option shapes from JS, opening a database at an unusable path, or wrapper/engine version drift; the operation named before the colon is the API that failed.","solutions":["Identify the failing operation from the prefix before the first colon, then treat the suffix as the authoritative native error string","Check the JS arguments passed to that exact API (types, required options)","For open/prepare failures, validate the database path and SQL text before calling","Upgrade the JS and native halves of the binding together"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isBindingWrapperError(e: unknown): e is Error {\n  return e instanceof Error && e.message.includes(': ');\n}","tryCatchPattern":"try { db.open(); } catch (e) { const msg = String((e as Error).message); const op = msg.slice(0, msg.indexOf(': ')); const cause = msg.slice(msg.indexOf(': ') + 2); console.error(`${op} failed: ${cause}`); }","preventionTips":["Validate option objects before passing them to binding APIs","Treat the suffix after the first colon as the authoritative native error","Log full messages - the prefix names the binding call to fix"],"tags":["javascript","node","napi","bindings","error-mapping"],"backgroundTag":"napi-error-mapping","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}