Skip to content

Fix webapp copy HTML crash due to destroyed borrowed PyProxy#358

Merged
henryiii merged 3 commits into
mainfrom
copilot/fix-webapp-copy-bug
Apr 4, 2026
Merged

Fix webapp copy HTML crash due to destroyed borrowed PyProxy#358
henryiii merged 3 commits into
mainfrom
copilot/fix-webapp-copy-bug

Conversation

Copilot AI commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Clicking "copy HTML" in the webapp throws a pyodide.ffi.JsException because families_dict is a borrowed attribute proxy of collected, and collected.destroy() is called in the finally block — automatically invalidating families_dict before it can be reused.

Changes

  • Call .copy() on the borrowed proxy immediately after access, making it an independent owned PyProxy that survives collected's destruction.
  • Add a destroyProxy() helper that safely calls .destroy() on a PyProxy | null and swallows errors, replacing repeated ad-hoc try/catch patterns.
  • Track families_dict and results_list as let locals outside the try block so they can be destroyed on error paths if they were never saved to state. After a successful setState, locals are nulled to prevent double-destroy.
  • handleRepoChange() and handleRefChange() now destroy existing stored proxies before nullifying them, preventing leaks when the user changes repo or ref.
  • Added componentWillUnmount() to destroy stored proxies when the component unmounts.

Copilot AI linked an issue Apr 4, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix copy HTML error in webapp Fix webapp copy HTML crash due to destroyed borrowed PyProxy Apr 4, 2026
Copilot AI requested a review from henryiii April 4, 2026 04:47
@henryiii henryiii requested a review from Copilot April 4, 2026 05:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Pyodide PyProxy lifetime issue in the React webapp where “Copy HTML” could crash due to a borrowed proxy becoming invalid after collected.destroy() runs.

Changes:

  • Convert (collected as any).families from a borrowed attribute proxy into an owned proxy by calling .copy() immediately.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/repo-review-app/repo-review-app.tsx Outdated
collected = collect_checks(pyodide, pyPackage);
const results_list = run_process(pyodide, pyPackage, collected) as any;
const families_dict = (collected as any).families;
const families_dict = (collected as any).families.copy();

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling .copy() here makes families_dict an owned PyProxy that won’t be auto-invalidated when collected.destroy() runs, but it also means it won’t be auto-freed. If an exception is thrown after this line (before pyFamilies is stored in state), or when repo/ref changes clear pyFamilies/pyChecks, the proxy can be leaked. Consider tracking families_dict/results_list in locals and explicitly .destroy() them on error paths, and destroying existing stored proxies when clearing them (e.g., in handleRepoChange/handleRefChange or unmount cleanup).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 16d8b41. Changes made:

  • Added a destroyProxy(proxy) helper that safely calls .destroy() and swallows errors, replacing all ad-hoc try/catch patterns.
  • handleCompute: families_dict/results_list are now let locals declared before the try. In the catch block they are destroyed if they were never saved to state. After setState succeeds, locals are nulled to prevent double-destroy. Old proxies are now destroyed via destroyProxy (no more nested try/catch).
  • handleRepoChange/handleRefChange: destroy existing stored proxies before setting them to null.
  • Added componentWillUnmount to destroy stored proxies when the component unmounts.
  • finally block simplified to use destroyProxy for collected and pyPackage.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup!

@henryiii henryiii marked this pull request as ready for review April 4, 2026 05:17
@henryiii henryiii merged commit 7ca5b64 into main Apr 4, 2026
13 checks passed
@henryiii henryiii deleted the copilot/fix-webapp-copy-bug branch April 4, 2026 05:18
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.

Webapp copy bug

3 participants