diff --git a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs index 64f87d60..d7a1b8f0 100644 --- a/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs @@ -1099,7 +1099,8 @@ public sealed partial class DetailsIslandViewModel : ViewModelBase, IDisposable } catch (Exception ex) { - failures.Add($"{fileName}: {ex.Message}"); + // Keep the exception type in the message so an intermittent failure is analyzable. + failures.Add($"{fileName}: {ex.GetType().Name}: {ex.Message}"); } } diff --git a/src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml.cs b/src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml.cs index decd3fa2..52f95286 100644 --- a/src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml.cs +++ b/src/ClaudeDo.Ui/Views/Islands/DetailsIslandView.axaml.cs @@ -81,14 +81,28 @@ public partial class DetailsIslandView : UserControl if (items is null) return; var files = new List<(string FileName, System.IO.Stream Content)>(); - foreach (var item in items) + try { - if (item is IStorageFile sf) + foreach (var item in items) { - var stream = await sf.OpenReadAsync(); - files.Add((sf.Name, stream)); + if (item is IStorageFile sf) + { + var stream = await sf.OpenReadAsync(); + files.Add((sf.Name, stream)); + } } } + catch (Exception ex) + { + // Opening the dropped stream can fail (shell IO, file lock) before AddFilesAsync + // ever runs; surface it with the exception type so the next occurrence is analyzable + // instead of vanishing as an unobserved async-void fault. + _vm.DropStatus = string.Format( + ClaudeDo.Ui.Localization.Loc.T("details.attachments.dropReadError"), + $"{ex.GetType().Name}: {ex.Message}"); + foreach (var (_, s) in files) await s.DisposeAsync(); + return; + } if (files.Count == 0) return;