Skip to content

fix(app): swallow URIError in assistant file link parser on bare '%'#1149

Open
Elliotwu-7 wants to merge 1 commit into
getpaseo:mainfrom
Elliotwu-7:fix/safe-decode-uri-component
Open

fix(app): swallow URIError in assistant file link parser on bare '%'#1149
Elliotwu-7 wants to merge 1 commit into
getpaseo:mainfrom
Elliotwu-7:fix/safe-decode-uri-component

Conversation

@Elliotwu-7
Copy link
Copy Markdown

Closes #1148.

Problem

`decodeURIComponent` throws `URIError: URI malformed` whenever a `%` in the input is not followed by two hex digits — common in tool output (`100% packet loss`, `0% off`), Windows env-var refs (`%PATH%`), and similar strings users routinely pipe through agents.

In `packages/app/src/assistant-file-links/parse.ts` two of those calls run on raw URL pathnames without a try/catch:

  • `parseAssistantFileLink` (was line 353)
  • `normalizeFileUrlPath` (was line 662)

`new URL("/tmp/100% packet loss", "http://paseo.invalid")\` does not throw — the bare `%` is preserved in `pathname`. The unguarded `decodeURIComponent` then throws and the exception escapes the React tree, unmounting the agent route. Result: clicking into the agent leaves a blank/black screen, and if it was the last route the next launch reproduces it from Local Storage.

A complementary helper, `safeDecodeURIComponent`, already exists in `packages/app/src/utils/host-routes.ts` (`decodeSegment`, lines 38–44) for the same reason. The parser should follow the same pattern.

Change

  • Add a local `safeDecodeURIComponent` in `parse.ts` that returns the input unchanged on `URIError`.
  • Use it at the two call sites above.
  • Add a regression test asserting that `parseAssistantFileLink` / `parseFileProtocolUrl` do not throw on `/tmp/100% packet loss`, `/Users/test/project/0% off`, `/var/log/%PATH%/x.log`, `file:///tmp/100% packet loss`.

Net diff: 2 files, +29 −2.

Repro (smallest, no app needed)

```js
const u = new URL('/tmp/100% packet loss', 'http://paseo.invalid'); // succeeds
decodeURIComponent(u.pathname); // throws URIError: URI malformed
```

Full UX repro:

  1. Run an agent that shells out something like `ping -c 5 unreachable.invalid`; the tool result includes `100% packet loss`.
  2. Quit Paseo, relaunch, click into that agent.
  3. Renderer logs `Uncaught URIError: URI malformed` and the agent view is blank.

QA / testing evidence

Vitest:

```
$ npx vitest run packages/app/src/assistant-file-links/parse.test.ts
Test Files 1 passed (1)
Tests 35 passed (35)
```

Full app suite vs. `main` (same machine, same install):

Branch Tests Errors (pre-existing env issues — playwright browser missing, jsdom localStorage)
`main` 1759 passed 33
this branch 1760 passed 33

The +1 is the new regression test. Pre-existing errors are unrelated to this change (they reproduce on `main` with the same install and have nothing to do with the modified files).

`npm run typecheck --workspace=@getpaseo/app`: passes.
`npm run lint --workspace=@getpaseo/app`: identical pre-existing failures on `main` and this branch (`223 problems / 7 errors / 216 warnings`, all in unrelated React component files).

End-to-end on macOS desktop (Paseo 0.1.80, arm64): I confirmed the same root cause out-of-band by replacing each illegal `%` in the underlying session jsonl with `%`; the agent then loaded normally with no `URIError` in `~/Library/Logs/Paseo/main.log`. The patched code is logically equivalent (the parser now returns null/raw instead of throwing), so the same agent will load without needing the data workaround.

Tested only on macOS desktop. I did not test iOS, Android, or web builds — the change is in shared parser code with no platform-specific paths, so I expect the behavior to be uniform, but I can't verify it without those build environments.

Notes

  • No UI changes — this is an internal exception-swallowing fix; nothing to screenshot.
  • Behavior preserved for valid percent-escapes: `%20` etc. continue to decode the same way.
  • The two call sites previously assumed their input was always valid percent-encoded. Returning the unchanged input on failure matches the conservative intent (downstream code re-validates the path against the workspace anyway).

… '%'

decodeURIComponent throws on '%' not followed by two hex digits. The two
calls inside parseAssistantFileLink and normalizeFileUrlPath had no
try/catch, so any timeline message containing strings like '100% packet
loss' (ping output), '%PATH%' or '0% off' could escape into the React
tree and unmount the agent route, leaving the renderer blank.

Wrap both calls in a local safeDecodeURIComponent that returns the input
unchanged when decoding fails, mirroring the helper already used in
host-routes.ts.

Closes getpaseo#1148
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.

Renderer crashes with URIError: URI malformed when timeline contains '%' followed by non-hex (e.g. '100% packet loss')

1 participant