Skip to content

fix(file-explorer): show remote import failure reasons - #9897

Closed
jae-heo wants to merge 6 commits into
stablyai:mainfrom
jae-heo:fix/file-explorer-import-failure-reasons
Closed

jae-heo wants to merge 6 commits into
stablyai:mainfrom
jae-heo:fix/file-explorer-import-failure-reasons

Conversation

@jae-heo

@jae-heo jae-heo commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #9896.

  • Show the unique failure reasons already returned by file Explorer imports in the existing error toast.
  • Make runtime upload failures state the 25 MB per-file and 100 MB aggregate limits.
  • Avoid the empty file label previously produced when a top-level dropped file exceeds the per-file limit.
  • Add regression coverage for an 80 MB file and for renderer failure-message formatting.

Screenshots

No screenshot attached. This is a text-only extension of the existing error toast: its title is unchanged and its description now contains the actionable backend reason. No user data or local paths are included in this PR.

Testing

  • pnpm lint — full lint reaches pre-existing failures on current main: a non-exhaustive switch in skill-freshness-group.tsx and missing localization keys in unrelated files. Changed-file oxlint, type-aware oxlint, reliability gates, max-lines, localization coverage, styled-scrollbar, bundled-guide, and skill-manifest checks pass.
  • pnpm typecheck
  • pnpm test — 3,218 files passed; 34,127 tests passed; 7 files and 58 tests skipped
  • pnpm build
  • Added high-quality tests that would catch regressions

AI Review Report

Reviewed the native desktop drop path, local import path, paired-runtime staging path, and SSH-backed import path. The actionable reason was already preserved through the main-process and authenticated runtime results but was discarded at the final renderer feedback seam. The change therefore leaves routing, ownership, destination planning, and the runtime RPC protocol unchanged.

The review checked repeated failures, empty reasons, an oversized top-level file, aggregate-size failures, and whether the file body is opened before rejecting an oversized file. Repeated reasons are deduplicated so a multi-file failure does not flood the toast, while distinct reasons remain visible.

Cross-platform review covered macOS, Linux, and Windows. No shortcut, shell command, platform path separator, native API, or Electron platform behavior changes. Local, paired-runtime, and SSH-backed imports continue to use their existing implementations.

Security Audit

Reviewed error provenance, input handling, paths, authentication, IPC, secrets, dependencies, and command execution.

  • The UI only displays reasons returned by the existing import operation to the user who initiated it.
  • Paired-runtime reasons continue to cross the existing authenticated runtime boundary.
  • No new IPC or RPC method, filesystem authority, network request, dependency, command execution, logging, telemetry, or credential storage was added.
  • Limit checks still happen before opening an oversized file, and the regression test verifies this.
  • Error details are shown locally in a transient toast and are not persisted or sent to a new destination.

No follow-up security work was identified.

Notes

  • The 25 MB per-file and 100 MB aggregate limits are unchanged; this PR only names them and surfaces their failures.
  • The full-lint failures described above are reproducible on the upstream base and do not touch files changed by this PR.
  • X/Twitter handle: N/A

ELI5

Failed remote file imports showed a vague toast with little detail. The error message now includes the real reasons (including size limits) so you know why the drop or upload failed.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d5a49cfd-9ca0-48f3-a6f1-34dbe9436691

📥 Commits

Reviewing files that changed from the base of the PR and between 31bfc63 and 32d9488.

📒 Files selected for processing (2)
  • src/main/ipc/filesystem-import.test.ts
  • src/main/ipc/filesystem-mutations.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/ipc/filesystem-mutations.ts
  • src/main/ipc/filesystem-import.test.ts

📝 Walkthrough

Walkthrough

Remote import size thresholds now derive from configured megabyte limits and produce specific per-file or total-limit errors, with updated coverage. File import failure notifications now use a shared formatter that localizes failure counts and deduplicates non-empty reasons before displaying toast descriptions.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: showing remote file import failure reasons in File Explorer.
Description check ✅ Passed The description covers the summary, testing, review, security, platform checks, and notes, with clear explanations for unavailable screenshot and lint results.
Linked Issues check ✅ Passed The changes satisfy issue #9896 by surfacing unique failure reasons, naming upload limits, fixing empty labels, and preserving existing protocols.
Out of Scope Changes check ✅ Passed The implementation and tests remain within the linked issue scope and do not introduce unrelated protocol, dependency, platform, or security changes.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/renderer/src/components/right-sidebar/file-explorer-import-feedback.test.ts (1)

14-24: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover trim-aware deduplication.

Add a reason such as ' Permission denied ' alongside 'Permission denied'; the current test does not verify that trimming also prevents whitespace-only duplicates.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 261e01a0-749e-40ab-a3ff-ee3ad2469b11

📥 Commits

Reviewing files that changed from the base of the PR and between 300ee19 and 8a11fbb48ce66058722b86b7685d955c8532ddc4.

📒 Files selected for processing (5)
  • src/main/ipc/filesystem-import.test.ts
  • src/main/ipc/filesystem-mutations.ts
  • src/renderer/src/components/right-sidebar/file-explorer-import-feedback.test.ts
  • src/renderer/src/components/right-sidebar/file-explorer-import-feedback.ts
  • src/renderer/src/components/right-sidebar/useFileExplorerImport.ts

Comment thread src/main/ipc/filesystem-import.test.ts Resolved
@jae-heo
jae-heo force-pushed the fix/file-explorer-import-failure-reasons branch from 8a11fbb to c16443a Compare July 24, 2026 06:09
@nwparker nwparker added the bug Something isn't working label Jul 27, 2026
@brennanb2025

Copy link
Copy Markdown
Contributor

Taking a look!

Sonner renders string descriptions with collapsed whitespace, so the
newline-joined reasons showed as run-on text; pre-line restores the
per-line format. Cap distinct reasons at 5 with an ellipsis line so
path-bearing reasons (per-file EACCES) cannot fill the screen.
Top-level dropped files staged with relativePath '' rendered failure
reasons with an empty or generic label now that reasons reach the toast
('File exceeds...', "File changed during upload staging: ''"). Thread
the source basename as a display-only name so every staging message
names the real file while the staged entry keeps its '' relativePath;
same fallback for the directory root's escape/type messages.
Collapse interior whitespace per reason so a newline-bearing filename
cannot defeat the line cap or forge an extra toast line; truncate only
when the ellipsis actually saves a line; keep the multi-line description
up for 60s (sonner's 4s default is unreadable for path-bearing reasons,
matching the store-slice error toast precedent); pin the cap boundary.
@brennanb2025

Copy link
Copy Markdown
Contributor

Thanks @jae-heo — clean, well-scoped fix; correct root cause (the reason was already carried through the import results and only dropped at the toast seam). Verified end-to-end against a real SSH workspace, and pushed small follow-up commits on top:

  • 815163e0 — render one reason per line (scoped whitespace-pre-line on the toast description; sonner was collapsing the \n separators) and cap distinct reasons with an ellipsis so a large drop can't fill the screen.
  • 3c0f44e9 — name the file in top-level staging failure reasons ('large.bin' exceeds the 25 MB remote import limit instead of a generic label), keeping the staged entry's wire relativePath unchanged.
  • ee02ccdd — harden the line handling: collapse interior whitespace per reason so a newline-bearing filename can't forge an extra toast line or defeat the cap; truncate only when the ellipsis actually saves a line; hold the failure toast for 60s (matching the repo's existing error-toast duration precedent) so multi-line reasons are readable. The 60s duration is a small behavior call — happy to revert if you'd rather keep the 4s default.
  • 31bfc631 — two test hardenings pinning dedup-before-cap order and the absent description key.

Reproduction (before → after)

Before (base): a failed drag-import into a read-only remote directory shows only the count — no way to tell why:

before: no reason

After (head): the toast surfaces the actionable reason:

after: reason shown

Multi-file failures de-duplicate repeated reasons into one line:

dedup: two files, one reason

Validation

  • Real SSH workspace (Linux container): failure toast shows title + reason with pre-line applied; drop into a writable dir imports with no failure toast; a 30 MB file imports fine over SSH (the 25/100 MB budget correctly applies only to runtime staging uploads).
  • Runtime staging IPC: oversized single file → 'big-30mb.bin' exceeds the 25 MB remote import limit; oversized directory → Remote import exceeds the 100 MB total limit.
  • Local git repo and folder workspace: imports unaffected, no failure toast.
  • typecheck exit 0 · changed-file oxlint clean · changed-code quality gate (incl. React Doctor) 0 new findings · 133 unit tests pass across import/runtime/SSH suites · perf audit clean (failure-path-only; early-reject before file reads preserved and regression-tested).
  • Review loop: two independent reviewers per round until both returned clean.

@greptile-apps

greptile-apps Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR surfaces actionable backend failure reasons in the file-explorer import error toast, which previously only showed a file count. It also improves size-limit error copy, fixes empty file labels in error messages for top-level dropped files and filesystem-root paths, and adds a getFileExplorerImportFailureToast helper with deduplication, newline normalization, and a capped line count for multi-file failures.

  • Renderer: a new getFileExplorerImportFailureToast function deduplicates per-file reasons, collapses embedded newlines, caps at 5+ellipsis when more than 6 distinct reasons exist, and passes the result to toast.error with descriptionClassName: 'whitespace-pre-line' and a 60-second duration (confirmed valid props in sonner 2.0.7).
  • Main process: stageFileEntry now accepts a displayName option so top-level files show their filename in errors; assertRemoteUploadBudget messages now name the per-file (25 MB) and aggregate (100 MB) limits explicitly; stageDirectoryEntries uses a dirDisplayPath fallback chain to avoid empty labels for the root directory.
  • Tests: regression coverage added for an 80 MB oversized file (verifying the file is never opened), a filesystem-root drop, and the full behaviour of getFileExplorerImportFailureToast (dedup, normalization, cap boundaries).

Confidence Score: 5/5

Safe to merge — the change is narrowly scoped to error message copy and toast formatting with no routing, IPC protocol, security boundary, or data-path logic modified.

The main-process changes carefully separate the display-only displayName path from the relativePath serialised into the staged-entry protocol. The descriptionClassName prop is confirmed valid in sonner 2.0.7. Deduplication and cap logic are fully covered by new unit tests including the exact truncation boundary. Regression tests verify oversized files are rejected before open() is called.

Files Needing Attention: No files require special attention.

Important Files Changed

Filename Overview
src/renderer/src/components/right-sidebar/file-explorer-import-feedback.ts New helper that formats the failure toast: deduplicates and normalises reasons, applies a 5-reason cap with ellipsis, and omits the description entirely when all reasons are blank.
src/renderer/src/components/right-sidebar/useFileExplorerImport.ts Replaces inline toast construction with getFileExplorerImportFailureToast; adds descriptionClassName and 60s duration. Both are valid ExternalToast fields in sonner 2.0.7.
src/main/ipc/filesystem-mutations.ts Introduces displayName option, separates entryRelativePath from displayPath, and updates assertRemoteUploadBudget with explicit MB figures. No change to security checks or protocol.
src/renderer/src/components/right-sidebar/file-explorer-import-feedback.test.ts New test file covering single failure, newline collapsing, deduplication, empty description, dedup-before-cap, cap with ellipsis, and the truncation boundary.
src/main/ipc/filesystem-import.test.ts Adds regression tests for 80 MB oversized file, filesystem-root display label, and updated expected messages for aggregate-size and path-escape failures.

Reviews (2): Last reviewed commit: "fix(file-explorer): label filesystem-roo..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d113ca3d-adeb-411f-97bc-92273e4112ca

📥 Commits

Reviewing files that changed from the base of the PR and between c16443a and 31bfc63.

📒 Files selected for processing (5)
  • src/main/ipc/filesystem-import.test.ts
  • src/main/ipc/filesystem-mutations.ts
  • src/renderer/src/components/right-sidebar/file-explorer-import-feedback.test.ts
  • src/renderer/src/components/right-sidebar/file-explorer-import-feedback.ts
  • src/renderer/src/components/right-sidebar/useFileExplorerImport.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/ipc/filesystem-import.test.ts
  • src/renderer/src/components/right-sidebar/useFileExplorerImport.ts

Comment thread src/main/ipc/filesystem-mutations.ts Resolved
@jae-heo

jae-heo commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough validation and follow-up improvements! The 60-second duration makes sense to me for multi-line, path-bearing error messages, so let's keep it.

@brennanb2025

Copy link
Copy Markdown
Contributor

Electron validation — exact PR head 32d9488

pr9897-remote-import-failure.png

  • Launched the PR worktree in an isolated Electron profile and verified app identity: pr-9897-review @ fix/file-explorer-import-failure-reasons.
  • Rendered the changed formatting helper through the real Sonner toaster in File Explorer context. The failure count and actionable 25 MB reason are both visible and readable.
  • No console or page errors occurred during the visual check.
  • pnpm build:relay passed for Linux and other targets. End-to-end SSH drop validation was not completed because Docker Desktop's backend timed out on every API request and its supported restart path could not recover it; no disposable container was created, and temporary SSH keys were removed. This screenshot is visual evidence only, not a substitute for the blocked SSH transport gate.

@jae-heo

jae-heo commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

@brennanb2025 Thanks again for the review and follow-up commits.

This PR now conflicts with main after #14703 split the filesystem IPC code. Updating it would require porting the runtime-upload changes into the new modules rather than just resolving a trivial rebase conflict.

Before I do that work, could you confirm whether this fix is still wanted and whether you would like me to refresh the PR? If so, I will rebase it, port the changes to the new structure, and rerun the relevant checks. The fork PR workflows will then need maintainer approval to run.

@nwparker

Copy link
Copy Markdown
Contributor

Thank you, @jae-heo! You were right that the explorer threw away the failure reason the import pipeline already returns. Main has changed a lot since this PR (the import handlers moved and the per-file limit is now 2 GB), so we rebuilt the fix in #33831 on the current code. That fix shows the shared reason in the file explorer, terminal drop and editor drop toasts, and keeps raw host paths out of the toast. You're credited as co-author on the commit. Thanks for the clear report and for pointing at the right seam!

@nwparker nwparker closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: File explorer hides remote import failure reasons

3 participants