From 163e51ccca5f0a6f016ecd9a13d5d5c13cf6ae4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mihai=20-=20Alexandru=20Chindri=C8=99?= Date: Sun, 1 Mar 2026 00:01:02 +0200 Subject: [PATCH 1/5] fix: release write lock before showing blocking error dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a recording fails, the error handler acquires state_mtx.write() and then calls dialog.blocking_show(), holding the write lock for the entire duration the user is looking at the error popup. Any attempt to start a new recording blocks at state_mtx.read() indefinitely, forcing the user to quit and relaunch the app. Fix: run handle_recording_end() inside a scoped block so the write lock is dropped before the blocking dialog is shown. This allows users to immediately start a new recording after dismissing the error dialog. Closes #1535 (partial — fixes the secondary deadlock, not the root AVAssetWriter/WriterFailed error) --- apps/desktop/src-tauri/src/recording.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index d65bce27fc..0e3efc48df 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -1057,13 +1057,23 @@ pub async fn start_recording( let _ = RecordingEvent::Stopped.emit(&app); } Err(e) => { - let mut state = state_mtx.write().await; - let _ = RecordingEvent::Failed { error: e.to_string(), } .emit(&app); + { + let mut state = state_mtx.write().await; + handle_recording_end( + app.clone(), + Err(e.to_string()), + &mut state, + project_file_path, + ) + .await + .ok(); + } + let mut dialog = MessageDialogBuilder::new( app.dialog().clone(), "An error occurred".to_string(), @@ -1076,10 +1086,6 @@ pub async fn start_recording( } dialog.blocking_show(); - - handle_recording_end(app, Err(e.to_string()), &mut state, project_file_path) - .await - .ok(); } } } From 7beab87ecd1b1e7685b49689f6dffc1558227862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mihai=20-=20Alexandru=20Chindri=C8=99?= Date: Sun, 1 Mar 2026 00:10:57 +0200 Subject: [PATCH 2/5] fix: reuse error string in recording failure path --- apps/desktop/src-tauri/src/recording.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index 0e3efc48df..95fab688a0 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -1057,8 +1057,9 @@ pub async fn start_recording( let _ = RecordingEvent::Stopped.emit(&app); } Err(e) => { + let error = e.to_string(); let _ = RecordingEvent::Failed { - error: e.to_string(), + error: error.clone(), } .emit(&app); @@ -1066,7 +1067,7 @@ pub async fn start_recording( let mut state = state_mtx.write().await; handle_recording_end( app.clone(), - Err(e.to_string()), + Err(error.clone()), &mut state, project_file_path, ) @@ -1077,7 +1078,7 @@ pub async fn start_recording( let mut dialog = MessageDialogBuilder::new( app.dialog().clone(), "An error occurred".to_string(), - e.to_string(), + error, ) .kind(tauri_plugin_dialog::MessageDialogKind::Error); From 1defd58867b93f8df6235914a175948d4dac5ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chindri=C8=99=20Mihai=20-=20Alexandru?= Date: Sun, 1 Mar 2026 00:15:21 +0200 Subject: [PATCH 3/5] Update apps/desktop/src-tauri/src/recording.rs Co-authored-by: tembo[bot] <208362400+tembo[bot]@users.noreply.github.com> --- apps/desktop/src-tauri/src/recording.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index 95fab688a0..95bd48d994 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -1078,7 +1078,12 @@ pub async fn start_recording( let mut dialog = MessageDialogBuilder::new( app.dialog().clone(), "An error occurred".to_string(), - error, + if let Some(window) = CapWindowId::Main + .get(&app) + .or_else(|| CapWindowId::RecordingControls.get(&app)) + { + dialog = dialog.parent(&window); + } ) .kind(tauri_plugin_dialog::MessageDialogKind::Error); From 60389f13761cfd5fc7f953bd8d17d6b303a8be25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chindri=C8=99=20Mihai=20-=20Alexandru?= Date: Sun, 1 Mar 2026 00:20:31 +0200 Subject: [PATCH 4/5] Update apps/desktop/src-tauri/src/recording.rs Co-authored-by: tembo[bot] <208362400+tembo[bot]@users.noreply.github.com> --- apps/desktop/src-tauri/src/recording.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index 95bd48d994..1f03c7416b 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -1078,6 +1078,20 @@ pub async fn start_recording( let mut dialog = MessageDialogBuilder::new( app.dialog().clone(), "An error occurred".to_string(), + error, + ) + .kind(tauri_plugin_dialog::MessageDialogKind::Error); + + if let Some(window) = CapWindowId::Main + .get(&app) + .or_else(|| CapWindowId::RecordingControls.get(&app)) + { + dialog = dialog.parent(&window); + } + + dialog.blocking_show(); + app.dialog().clone(), + "An error occurred".to_string(), if let Some(window) = CapWindowId::Main .get(&app) .or_else(|| CapWindowId::RecordingControls.get(&app)) From ec8b06b8d11f3be946c5da5ab41ad74f94fba3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mihai=20-=20Alexandru=20Chindri=C8=99?= Date: Sun, 1 Mar 2026 00:22:09 +0200 Subject: [PATCH 5/5] fix: prefer main window for recording error dialog parent --- apps/desktop/src-tauri/src/recording.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index 1f03c7416b..04cd546dd3 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -1089,22 +1089,6 @@ pub async fn start_recording( dialog = dialog.parent(&window); } - dialog.blocking_show(); - app.dialog().clone(), - "An error occurred".to_string(), - if let Some(window) = CapWindowId::Main - .get(&app) - .or_else(|| CapWindowId::RecordingControls.get(&app)) - { - dialog = dialog.parent(&window); - } - ) - .kind(tauri_plugin_dialog::MessageDialogKind::Error); - - if let Some(window) = CapWindowId::RecordingControls.get(&app) { - dialog = dialog.parent(&window); - } - dialog.blocking_show(); } }