github / github/app

[Bugs] App crashes in a loop on launch (Wry InvalidUri panic).

Open
#1,171 1 comment 0 reactions 0 assignees View on GitHub
Bugs
Dominant language
No language data
Stars
2.1k
Forks
153
PR merge metrics
No merged PRs in 30d

Description

**Mood:** 😊
**Category:** Bugs

App crashes in a loop on launch (Wry InvalidUri panic).

A persisted "open canvas" reopens a browser canvas on startup with an unescaped
URL. The app calls .unwrap() on http::Uri::try_from(url) inside an extern "C"
WebView2 callback; the URL is invalid (raw spaces from a folder path, and in
another case a # fragment), so it panics with InvalidUri(InvalidFormat). The
panic can't unwind across the FFI boundary -> hard abort (panicking.rs:225). It
recurs every launch and the error popup re-triggers the crash, so the app is
unusable until rows are manually deleted from session_open_canvases in data.db.

Build: copilot-desktop-gh-2.94.0, Wry wry-0.55.1, Windows 11.

Error messages:
called `Result::unwrap()` on an `Err` value: http::Error(InvalidUri(InvalidFormat)) (wry-0.55.1)
panic in a function that cannot unwind (core/src/panicking.rs:225:5)

Suggested fix: percent-encode/normalize URLs before passing to the webview,
don't unwrap() the URI parse, and catch_unwind in the navigation callback.

# Bug Report: App crash loop from persisted canvas with unescaped URL

**Title:** App crash loop: persisted canvas with unescaped URL panics Wry (`InvalidUri(InvalidFormat)`) on launch

**Severity:** High — unrecoverable crash loop; app must be killed and DB hand-edited to recover.

## Environment
- App: GitHub Copilot desktop (`com.github.githubapp`), build `copilot-desktop-gh-2.94.0`
- OS: Windows 11
- WebView: WebView2 (Wry `wry-0.55.1`)

## Summary
Open browser canvases are persisted in `data.db` -> `session_open_canvases` with their
`input.url` stored **unescaped**. When the app reopens such a canvas on launch, it calls
`.unwrap()` on `http::Uri::try_from(url)` inside an `extern "C"` WebView2 navigation
callback. URLs that aren't valid RFC 3986 (raw spaces, or a `#` fragment) fail to parse,
the `unwrap()` panics, and because the panic can't unwind across the FFI boundary it
escalates to a hard abort. This happens **every launch**, producing an unrecoverable loop.

## Two malformed-URL triggers observed
1. **Unescaped spaces** — file URLs built from a path containing spaces were stored
literally, e.g.
`file:///C:/Users///.../dashboard.html`
(note raw spaces, not `%20`).
2. **Fragment URLs** — a single-page-app link (hash-routed) stored as
`https://host/App/#/Displays//...?starttime=...&asset=...`
`http::Uri` rejects the `#` fragment (and the query placed after it).

## Error messages
```
thread '<...>' panicked at wry-0.55.1/.../:
called `Result::unwrap()` on an `Err` value: http::Error(InvalidUri(InvalidFormat))
```
followed by:
```
panic in a function that cannot unwind
core/src/panicking.rs:225:5
```

## Steps to reproduce
1. Open a browser canvas whose URL contains an unescaped space or a `#` fragment.
2. Let it persist to `session_open_canvases` with `reopen: true`.
3. Restart the app -> it reopens the canvas -> Wry panics -> abort.
4. Relaunching repeats the crash (state is persistent).

## Impact
- Crash on startup; the in-app error popup re-triggers the abort when clicked.
- Canvas panel can't be closed because the app aborts first.
- Only recovery is killing all processes and deleting the offending rows from `data.db`
directly.

## Expected behavior
- URLs should be percent-encoded / normalized before being handed to the webview.
- The `http::Uri` parse must not `unwrap()` — handle `Err` gracefully (skip / restore-blank
the canvas, log, surface a non-fatal toast).
- Never let a panic cross the `extern "C"` webview callback (catch at the FFI boundary).

## Suggested fixes
1. Replace `http::Uri::try_from(url).unwrap()` with proper error handling at the navigation
call site.
2. Encode URLs when persisting/loading canvas `input.url` (e.g. `Url::parse` /
percent-encoding) so spaces and fragments are valid.
3. Wrap the WebView2 navigation callback body in `std::panic::catch_unwind` so a bad URL
degrades gracefully instead of aborting.
4. Validate `session_open_canvases.input.url` on load; drop/repair entries that don't parse.

## Workaround for affected users
Fully close the app, then delete rows from `session_open_canvases` in
`%USERPROFILE%\.copilot\data.db` (back it up first).

---
| Field | Value |
| --- | --- |
| App version | 1.0.1 |
| OS | Windows 10.0.26200 |
| Theme | GitHub |
| Path | /chat |
| Tenure | Day 1 |

Contributor guide

Open the contributing guide

Research direction

Start at the WebView2 navigation callback and its http::Uri::try_from(url).unwrap() call site; inspect how session_open_canvases URLs are loaded and persisted. Reproduce with a URL containing a space or #, then verify invalid entries no longer abort launch or require database deletion while valid canvases still reopen.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.