fix(store-node): surface permission errors from setStoreBlob/delStoreBlob#3718
fix(store-node): surface permission errors from setStoreBlob/delStoreBlob#3718calebcgates wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
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
setStoreBlob→src/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 withEACCES/EPERM/EROFS, the rejection bubbles through the unhandledipcMain.handle('setStoreBlob', ...)callback atsrc/main/main.ts:547, and Electron stringifies it across the IPC boundary as the unhelpful genericError: 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
setStoreBlobanddelStoreBlobintry/catchblocks that match the existing pattern used elsewhere in the same file (autoBackupat L54-66,backup()at L96-101,clearBackups()at L192-204 — all usetry { ... } catch (err) { logger.error('...', err) }). The catch:code+ the original error via the existinglogger.error(...)soelectron-logcaptures the actionable detail.EACCES/EPERM/EROFS) into a clearError("Cannot write attachment cache to '<path>': permission denied. Check that the chatbox userData directory is writable.", { cause: err }). Node'sError.cause(≥16.9, well within chatbox's pinnedengines.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 inERROR_HANDLING.md) reports both layers.ENOSPC,EIO, etc.).delStoreBlob, swallowsENOENT(race between the existingpathExists()pre-check andremove()is now explicitly idempotent) but surfacesEACCES/EPERMso genuine permission failures don't leave orphaned cache entries silently.Additional Notes
src/main/**.src/main/had no existing test coverage. The newsrc/main/store-node.test.tsmockselectron(app.getPath) andfs-extraso the suite runs under the existingpnpm exec vitest runinvocation without needing an Electron runtime. The vitest config (vitest.config.tsL13) already globssrc/**/*.{test,spec}.{ts,tsx}— no config change required. 7 tests, all green.setStoreBlobstill returns thefs.writeFileresult;delStoreBlobstill returnsundefinedwhen the file is absent or successfully removed. The only observable change is what surfaces when the disk write fails.try { ... } catch (err) { logger.error(...) }style used byautoBackup(L54),backup()(L96), andclearBackups()(L192-204) in the same file — no new convention introduced.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 originalErrorrather 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:
Please check the box below to confirm:
[x] I have read and agree with the above statement.