From 7dbb2209c866061fc0c31c821e38ca19546e3779 Mon Sep 17 00:00:00 2001 From: Mikhail Kilin Date: Thu, 5 Feb 2026 13:06:40 +0300 Subject: [PATCH] fix: use char boundaries instead of byte indices for UTF-8 strings in notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PANIC FIX: Notification preview truncation was using byte indices (`[..147]`) instead of char boundaries, causing panic when truncating UTF-8 strings containing multi-byte characters (Cyrillic, emoji, etc.). Error message: "byte index 147 is not a char boundary; it is inside 'п' (bytes 146..148)" Fix: - Replace `beautified.len() > 150` with `beautified.chars().count() > MAX_PREVIEW_CHARS` - Replace `&beautified[..147]` with `beautified.chars().take(MAX_PREVIEW_CHARS).collect()` - Add constant MAX_PREVIEW_CHARS = 147 for clarity This ensures we truncate at character boundaries, not byte boundaries, preventing panics on multi-byte UTF-8 sequences. Impact: Notifications for messages with Russian/emoji text crashed the app. Root cause: Classic Rust UTF-8 indexing mistake - slicing by bytes instead of characters. Co-Authored-By: Claude Sonnet 4.5 --- src/notifications.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/notifications.rs b/src/notifications.rs index fe3421d..14f35d9 100644 --- a/src/notifications.rs +++ b/src/notifications.rs @@ -164,9 +164,12 @@ impl NotificationManager { // Beautify media labels with emojis let beautified = Self::beautify_media_labels(text); - // Limit preview length - if beautified.len() > 150 { - format!("{}...", &beautified[..147]) + // Limit preview length (use char count, not byte count for UTF-8 safety) + const MAX_PREVIEW_CHARS: usize = 147; + let char_count = beautified.chars().count(); + if char_count > MAX_PREVIEW_CHARS { + let truncated: String = beautified.chars().take(MAX_PREVIEW_CHARS).collect(); + format!("{}...", truncated) } else { beautified }