Description
A chained .unwrap() sequence inside tokio::task::spawn_blocking in the OCR embedding pipeline can crash the entire processing task, silently dropping a whole batch of OCR results with no recovery path.
File: crates/daemon/src/pipeline/processing_ocr_results.rs (lines ~100-106)
Current Code
ust tokio::task::spawn_blocking(move || { embedding_model .lock() .unwrap() // panics if mutex is poisoned .generate_batch_embeddings(text_for_embeddings) .unwrap() // panics if embedding fails }).await .unwrap() // panics if spawn_blocking task panicked
Impact
When the innermost .unwrap() panics, spawn_blocking wraps it in a JoinError::Panic. The outer .await.unwrap() re-panics, terminating the entire async processing task. The receiver loop has no mechanism to restart, so the daemon silently stops processing OCR frames until restarted.
Suggested Fix
Replace .unwrap() calls with proper ? error propagation and handle errors at the call site. At minimum:
ust tokio::task::spawn_blocking(move || { embedding_model .lock() .map_err(|e| anyhow!("mutex poisoned: {e}"))? .generate_batch_embeddings(text_for_embeddings) .map_err(|e| anyhow!("embedding failed: {e}")) }).await .map_err(|e| anyhow!("spawn_blocking panicked: {e}"))?
This allows the error to be logged and the frame skipped rather than crashing the pipeline.
Description
A chained
.unwrap()sequence insidetokio::task::spawn_blockingin the OCR embedding pipeline can crash the entire processing task, silently dropping a whole batch of OCR results with no recovery path.File:
crates/daemon/src/pipeline/processing_ocr_results.rs(lines ~100-106)Current Code
ust tokio::task::spawn_blocking(move || { embedding_model .lock() .unwrap() // panics if mutex is poisoned .generate_batch_embeddings(text_for_embeddings) .unwrap() // panics if embedding fails }).await .unwrap() // panics if spawn_blocking task panickedImpact
When the innermost
.unwrap()panics,spawn_blockingwraps it in aJoinError::Panic. The outer.await.unwrap()re-panics, terminating the entire async processing task. The receiver loop has no mechanism to restart, so the daemon silently stops processing OCR frames until restarted.Suggested Fix
Replace
.unwrap()calls with proper?error propagation and handle errors at the call site. At minimum:ust tokio::task::spawn_blocking(move || { embedding_model .lock() .map_err(|e| anyhow!("mutex poisoned: {e}"))? .generate_batch_embeddings(text_for_embeddings) .map_err(|e| anyhow!("embedding failed: {e}")) }).await .map_err(|e| anyhow!("spawn_blocking panicked: {e}"))?This allows the error to be logged and the frame skipped rather than crashing the pipeline.