Skip to content

fix(store-node): surface permission errors from setStoreBlob/delStoreBlob#3718

Open
calebcgates wants to merge 1 commit into
chatboxai:mainfrom
calebcgates:fix/store-blob-surface-permission-errors
Open

fix(store-node): surface permission errors from setStoreBlob/delStoreBlob#3718
calebcgates wants to merge 1 commit into
chatboxai:mainfrom
calebcgates:fix/store-blob-surface-permission-errors

Conversation

@calebcgates

Copy link
Copy Markdown

Description

When a user attaches a file (PDF, DOCX, EPUB, pasted long text, etc.) to a chat, chatbox parses the content in the renderer and persists the parsed text to disk via the IPC handler setStoreBlobsrc/main/store-node.ts:230. Today, if the userData blob directory is unwritable — corporate-managed macOS profile, Windows running chatbox under a non-admin service account, AppData on a network share that disconnected, full-disk-encrypted volume locked, etc. — fs.ensureDir(...) rejects with EACCES/EPERM/EROFS, the rejection bubbles through the unhandled ipcMain.handle('setStoreBlob', ...) callback at src/main/main.ts:547, and Electron stringifies it across the IPC boundary as the unhelpful generic Error: An object could not be cloned. The user sees a silently-dropped attachment with no actionable feedback; Sentry receives only the post-IPC opaque error.

This PR wraps both setStoreBlob and delStoreBlob in try/catch blocks that match the existing pattern used elsewhere in the same file (autoBackup at L54-66, backup() at L96-101, clearBackups() at L192-204 — all use try { ... } catch (err) { logger.error('...', err) }). The catch:

  • Logs code + the original error via the existing logger.error(...) so electron-log captures the actionable detail.
  • Translates permission errors (EACCES / EPERM / EROFS) into a clear Error("Cannot write attachment cache to '<path>': permission denied. Check that the chatbox userData directory is writable.", { cause: err }). Node's Error.cause (≥16.9, well within chatbox's pinned engines.node: ">=20.0.0 <23.0.0") preserves the original errno + path so the renderer's existing Sentry handler (src/renderer/setup/global_error_handler.ts, documented in ERROR_HANDLING.md) reports both layers.
  • Re-throws all non-permission errors unchanged (preserves existing observability for ENOSPC, EIO, etc.).
  • For delStoreBlob, swallows ENOENT (race between the existing pathExists() pre-check and remove() is now explicitly idempotent) but surfaces EACCES/EPERM so genuine permission failures don't leave orphaned cache entries silently.

Additional Notes

  • First test for src/main/**. src/main/ had no existing test coverage. The new src/main/store-node.test.ts mocks electron (app.getPath) and fs-extra so the suite runs under the existing pnpm exec vitest run invocation without needing an Electron runtime. The vitest config (vitest.config.ts L13) already globs src/**/*.{test,spec}.{ts,tsx} — no config change required. 7 tests, all green.
  • No behaviour change on the happy path. setStoreBlob still returns the fs.writeFile result; delStoreBlob still returns undefined when the file is absent or successfully removed. The only observable change is what surfaces when the disk write fails.
  • Conforms to existing try { ... } catch (err) { logger.error(...) } style used by autoBackup (L54), backup() (L96), and clearBackups() (L192-204) in the same file — no new convention introduced.
  • Surgical scope. +26 / -3 lines in one source file. Happy to extend the same pattern to getStoreBlob / listStoreBlobKeys (read paths) in a follow-up if you'd like, though their failure modes are already more user-actionable (read failures already propagate the original Error rather than getting opaqued by IPC stringification of an awaited rejection).

Screenshots

N/A — backend/IPC change with no UI surface.

Contributor Agreement

By submitting this Pull Request, I confirm that I have read and agree to the following terms:

  • I agree to contribute all code submitted in this PR to the open-source community edition licensed under GPLv3 and the proprietary official edition without compensation.
  • I grant the official edition development team the rights to freely use, modify, and distribute this code, including for commercial purposes.
  • I confirm that this code is my original work, or I have obtained the appropriate authorization from the copyright holder to submit this code under these terms.
  • I understand that the submitted code will be publicly released under the GPLv3 license, and may also be used in the proprietary official edition.

Please check the box below to confirm:

[x] I have read and agree with the above statement.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b93644ff-fb61-4ab6-94aa-6909109fd223

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant