Skip to content

Commit 0b51a33

Browse files
committed
Fix: silence get_file_at FE/BE drift warning during async listing refresh
The 'frontend/backend index mismatch!' log_error in get_file_at was added as diagnostic to catch genuine drift, but it fires legitimately during the brief window between a directory-diff event arriving and the FE's cached `totalCount` being updated by the subsequent `getTotalCount` IPC. The user saw it in their move logs (cursor settled on index 29 in a listing that had already shrunk to 29 entries) — visually nothing was broken (FE handles `null` from getFileAt gracefully), but the log was noisy and triggered the opt-in error reporter. Two-pronged fix: - **Backend** (`get_file_at`): demote the out-of-bounds path from `crate::log_error!` (auto-reportable) to `log::debug!`. The breadcrumb is still in the file log when investigating cursor/selection bugs, but it no longer surfaces as an error to the user or in error reports. Updated the comment to explain the legitimate drift case. - **Frontend** (`buildMcpFileList` in FilePane.svelte): the loop iterating over the visible range to sync MCP context state used to skip null entries silently and continue. That meant for a backendStart=0, visibleRangeEnd=30 against a listing that had shrunk to 29, we'd make 30 IPC calls — only the last one out of bounds, but every iteration still paid the round-trip. Changed `if (entry) {push}` to `if (!entry) break`: null means the BE listing has fewer entries than our cached `totalCount` (a directory-diff is mid-flight), so stop iterating instead of paying for futile lookups. Tests: 1606 Rust, 1739 Svelte, clippy/svelte-check/eslint all green.
1 parent 72d3d7e commit 0b51a33

2 files changed

Lines changed: 21 additions & 14 deletions

File tree

apps/desktop/src-tauri/src/file_system/listing/operations.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,14 @@ pub fn get_file_at(listing_id: &str, index: usize, include_hidden: bool) -> Resu
243243
let result = visible_entries(&listing.entries, include_hidden).nth(index).cloned();
244244
if result.is_none() {
245245
let total = visible_entries(&listing.entries, include_hidden).count();
246-
// FE/BE index desync surfaces as broken cursor/selection. Use `log_error!` so
247-
// opt-in users help us catch the trigger conditions.
248-
crate::log_error!(
249-
"get_file_at: index {} out of bounds (listing {} has {} entries at {}) - frontend/backend index mismatch!",
246+
// Out-of-bounds is expected briefly after a mutation: the FE iterates over a
247+
// cached `totalCount` that may lag the BE listing during the async refetch
248+
// window opened by a `directory-diff` event. The FE handles `None` gracefully
249+
// (skips the entry, breaks the loop). Logged at debug so we still have the
250+
// breadcrumb when investigating cursor/selection bugs without firing crash
251+
// reports for legitimate drift.
252+
log::debug!(
253+
"get_file_at: index {} out of bounds (listing {} has {} entries at {}) — likely FE/BE drift after async listing refresh",
250254
index,
251255
listing_id,
252256
total,

apps/desktop/src/lib/file-explorer/pane/FilePane.svelte

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -764,16 +764,19 @@
764764
const backendIndex = backendStart + i
765765
if (backendIndex >= totalCount) break
766766
const entry = await getFileAt(listingId, backendIndex, includeHidden)
767-
if (entry) {
768-
files.push({
769-
name: entry.name,
770-
path: entry.path,
771-
isDirectory: entry.isDirectory,
772-
size: entry.size,
773-
recursiveSize: entry.recursiveSize,
774-
modified: entry.modifiedAt ? new Date(entry.modifiedAt * 1000).toISOString() : undefined,
775-
})
776-
}
767+
// Null means the listing on the BE has fewer entries than our cached
768+
// `totalCount` (a directory-diff is mid-flight). Stop here — keeps the
769+
// partial MCP state consistent and avoids trailing out-of-bounds calls
770+
// for the rest of the visible range.
771+
if (!entry) break
772+
files.push({
773+
name: entry.name,
774+
path: entry.path,
775+
isDirectory: entry.isDirectory,
776+
size: entry.size,
777+
recursiveSize: entry.recursiveSize,
778+
modified: entry.modifiedAt ? new Date(entry.modifiedAt * 1000).toISOString() : undefined,
779+
})
777780
}
778781
return files
779782
}

0 commit comments

Comments
 (0)