{"record":{"id":"97479acf60b744fa","repo":"tursodatabase/turso","slug":"latency-worker-panicked","errorCode":null,"errorMessage":"latency worker panicked","messagePattern":"latency worker panicked","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"perf/fts/src/latency.rs","lineNumber":68,"sourceCode":"                        result.rows += completed.rows;\n                        result.id_sum += completed.id_sum;\n                    }\n                    Ok::<_, anyhow::Error>((result, latencies))\n                })\n            })\n            .collect();\n        let start = Instant::now();\n        barrier.wait();\n        let outcomes: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();\n        let seconds = start.elapsed().as_secs_f64();\n        let mut measurement = Measurement {\n            result: RunResult::default(),\n            seconds,\n            latencies: Vec::with_capacity(queries),\n        };\n        for outcome in outcomes {\n            let (result, latencies) =\n                outcome.map_err(|_| anyhow::anyhow!(\"latency worker panicked\"))??;\n            measurement.result.queries += result.queries;\n            measurement.result.rows += result.rows;\n            measurement.result.id_sum += result.id_sum;\n            measurement.latencies.extend(latencies);\n        }\n        Ok(measurement)\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    use std::collections::HashSet;\n    use std::sync::Mutex;\n\n    use super::*;\n\n    #[test]\n    fn uses_distinct_threads_and_records_each_query_with_uneven_work() -> Result<()> {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/tursodatabase/turso/blob/8d4a589f8d13ac184700d2a8f724f27e1995be3b/perf/fts/src/latency.rs#L50-L86","documentation":"`measure` spawns one worker thread per session; if any worker panics while executing queries, its JoinHandle yields an Err which `measure` converts to this error. It signals that a benchmark thread crashed mid-run rather than the query itself returning a normal error.","triggerScenarios":"A worker thread passed to `measure` panics inside the user-supplied `execute` closure (e.g. index-out-of-bounds, unwrap on None, connection closed unexpectedly), making the scoped JoinHandle return an Err.","commonSituations":"A SQL executor bug or a panic in benchmark code running on a worker thread; a connection being closed or poisoned during the benchmark loop.","solutions":["Fix the panic inside the `execute` closure (look for unwrap/expect/indexing).","Check panic stderr output for the real panic message and location.","Avoid panicking APIs in `execute`; return `Result::Err` instead so the error propagates normally."],"exampleFix":"// before\nlet row = rows.get(i).unwrap();\n// after\nlet Some(row) = rows.get(i) else { return Ok(RunResult::default()) };","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| execute(session, rt))) {\n    Ok(res) => res,\n    Err(_) => return Err(anyhow::anyhow!(\"worker panicked; check execute closure for unwrap/index panics\")),\n}","preventionTips":["Avoid unwrap/expect/panic in the execute closure; return Result instead","Run the benchmark under a debugger or set RUST_BACKTRACE=1 to locate panics","Test execute with a single connection/single query before scaling up"],"tags":["benchmark","panic","threads","rust"],"backgroundTag":"thread-interrupted","analyzedSha":"8d4a589f8d13ac184700d2a8f724f27e1995be3b","analyzedAt":"2026-09-20T13:18:14.658Z","contentChangedAt":"2026-09-20T13:18:14.658Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}