Skip to content

Fix #126: stop note tiles from triggering ENOENT on undefined file path#130

Open
Hude06 wants to merge 1 commit into
collabs-inc:mainfrom
Hude06:fix/126-note-tile-undefined-readfile
Open

Fix #126: stop note tiles from triggering ENOENT on undefined file path#130
Hude06 wants to merge 1 commit into
collabs-inc:mainfrom
Hude06:fix/126-note-tile-undefined-readfile

Conversation

@Hude06

@Hude06 Hude06 commented Apr 15, 2026

Copy link
Copy Markdown

Fixes #126.

Root cause

Tracing the ENOENT from the issue:

  1. canvas-rpc.js:104 — RPC tileCreate defaults tileType to "note". For a note with no backing file, it falls through to createFileTile("note", x, y, undefined).

  2. tile-manager.js:626-628 — Builds the viewer webview URL with \tilePath=${encodeURIComponent(filePath)}`. encodeURIComponent(undefined)returns the literal string"undefined", so the URL becomes viewer.html?tilePath=undefined&tileMode=note`.

  3. viewer/src/App.tsx:108-114 — Parses tilePath from the URL. params.get("tilePath") returns the string "undefined". The if (tp) guard treats it as truthy and calls setSelectedPath("undefined").

  4. viewer/src/App.tsx:324 — Subsequently calls window.api.readFile("undefined"). The desktop bridge resolves the relative path against the app install dir, producing the path from the issue:

    ENOENT: no such file or directory, open 'C:\Users\…\AppData\Local\Programs\Collaborator\undefined'
    

Fix

Two surgical changes, both upstream of the IPC call:

collab-electron/src/windows/shell/src/tile-manager.js

Build the viewer URL with URLSearchParams and only set tilePath when filePath is a non-empty string. Note tiles without a backing file now get a viewer URL with no tilePath at all, so the viewer's existing if (!selectedPath) return; guard catches them naturally and never calls readFile.

collab-electron/src/windows/viewer/src/App.tsx

Defense in depth — treat the literal strings "undefined" and "null" as missing tilePath. This protects against any other caller that might still emit a stringified nullish value (e.g. older serialized state, third-party RPC callers).

What this does not do

This PR fixes the crash but does not implement in-memory note content. Note tiles created without a backing file will render an empty viewer rather than throwing. The viewer already accepts a tileMode query param but does not currently branch on it — adding real in-memory note rendering is a larger scope and belongs in a follow-up.

Verification

Repro from the issue:

  1. Create a note tile via the canvas tools.
  2. Before this PR: ENOENT error in the main process log, viewer fails to render.
  3. After this PR: viewer renders an empty tile, no error in the log.

When a note tile is created without a backing file, tile-manager built
the viewer webview URL with `encodeURIComponent(undefined)`, producing
the literal query string `tilePath=undefined`. The viewer then parsed
that as a truthy string and called `fs:readfile("undefined")`, which
the desktop bridge resolved against the app install dir and failed
with ENOENT (issue collabs-inc#126).

Two changes:

1. tile-manager.js: build the viewer URL with URLSearchParams and
   only set `tilePath` when filePath is a non-empty string. Note
   tiles without a backing file get a viewer URL with no tilePath.

2. viewer App.tsx: defense in depth — treat the literal strings
   "undefined" and "null" as missing tilePath, so any other caller
   that emits a stringified nullish value also no-ops cleanly.

Fixes collabs-inc#126
@yiliush

yiliush commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@Hude06

Hude06 commented Apr 15, 2026

Copy link
Copy Markdown
Author

I have read the Contributor License Agreement (CLA) and hereby sign the CLA.

chihirokajiwara-AI pushed a commit to chihirokajiwara-AI/collab-public that referenced this pull request May 10, 2026
When a note tile has no file path, the viewer would receive
tilePath=undefined in the URL, triggering an ENOENT error on
readFile. Now uses URLSearchParams and only sets tilePath when
it's a valid non-empty string. Also strengthened the viewer-side
guard to reject string literals "undefined" and "null".

Upstream: collabs-inc#130

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

Note tiles try to read an undefined file path and fail with ENOENT

2 participants