Serve a PHP error page and auto-recover when a site fails to start - #4246
Open
gcsecsey wants to merge 27 commits into
Open
Serve a PHP error page and auto-recover when a site fails to start#4246gcsecsey wants to merge 27 commits into
gcsecsey wants to merge 27 commits into
Conversation
…ase is locked" on Playground 3.1.45
…ayground-fix # Conflicts: # packages/data-liberation-agent/dist/mcp-server.bundle.mjs # packages/data-liberation-agent/dist/scripts/_validate.mjs # packages/data-liberation-agent/dist/scripts/carry-reconstruct-drive.mjs # packages/data-liberation-agent/dist/scripts/chunk-3QFGXLW4.mjs # packages/data-liberation-agent/dist/scripts/chunk-5ISMP4W6.mjs # packages/data-liberation-agent/dist/scripts/chunk-J2WXJEI3.mjs # packages/data-liberation-agent/dist/scripts/chunk-PXH76XU4.mjs
…' into gcsecsey/stu-1370-php-error-recovery # Conflicts: # apps/studio/src/ipc-handlers.ts
… journal mode Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…php-error-recovery
…ayground-fix # Conflicts: # packages/data-liberation-agent/dist/mcp-server.bundle.mjs
…very' into gcsecsey/stu-1370-php-error-recovery
…ayground-fix # Conflicts: # packages/data-liberation-agent/dist/mcp-server.bundle.mjs
…p-error-recovery # Conflicts: # packages/data-liberation-agent/dist/mcp-server.bundle.mjs # packages/data-liberation-agent/dist/scripts/carry-reconstruct-drive.mjs # packages/data-liberation-agent/dist/scripts/chunk-JSC2QBHK.mjs
…' into gcsecsey/stu-1370-php-error-recovery
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a “PHP error recovery” mode to Studio’s Playground (WASM) runtime startup path so a site can still become reachable when WordPress fatals during warm boot, by serving a lightweight error page on the site’s port and auto-retrying startup on .php changes.
Changes:
- Introduces a recovery server + PHP error parsing/classification, with a file watcher that retries startup after PHP edits.
- Updates running-state adoption and event propagation so “in recovery” sites remain effectively “running” in Studio despite the CLI reporting them stopped.
- Adds unit tests for parsing/classification and for running-state reconciliation; adds child-process logging to avoid crashes on stray unhandled errors.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| package-lock.json | Lockfile updates from dependency resolution changes. |
| apps/studio/src/tests/reconcile-running-state.test.ts | Adds coverage ensuring recovery-mode sites remain treated as running during reconciliation. |
| apps/studio/src/site-server.ts | Adds inErrorRecovery flag and ensures running-state adoption treats recovery sites as running. |
| apps/studio/src/modules/cli/lib/cli-events-subscriber.ts | Treats recovery sites as effectively running and adjusts emitted IPC site events accordingly. |
| apps/studio/src/lib/tests/php-error-recovery.test.ts | New unit tests for PHP error parsing/classification and recovery server lifecycle. |
| apps/studio/src/lib/php-error-recovery.ts | Implements error-page server, log parsing, recovery state, and file-watcher retry loop. |
| apps/studio/src/ipc-handlers.ts | Wires recovery into startServer/stopServer, serving the recovery page on startup PHP errors and notifying the renderer. |
| apps/cli/playground-server-child.ts | Adds global uncaughtException/unhandledRejection logging to avoid child crashes that would prevent recovery. |
Comments suppressed due to low confidence (2)
apps/studio/src/lib/php-error-recovery.ts:155
- The recovery URL is hardcoded to
http://localhost:${port}, which ignorescustomDomain/enableHttps. For sites using a custom domain, the UI will point at localhost instead of the configured domain, even though the proxy/domain should still be able to reach the port-bound recovery server.
const url = `http://localhost:${ port }`;
apps/studio/src/lib/php-error-recovery.ts:137
- If
siteServer.start()fails andstartErrorRecovery(...)also throws (e.g. the port is still busy, or the watcher/server fails to initialize), the async IIFE rejection is currently unhandled (void (async () => ...)()), which can produce an unhandled rejection and potentially crash/abort the main process.startErrorRecoveryshould be wrapped so recovery restart failures are handled and logged instead of escaping.
} catch {
// Still failing - re-serve the error page with the latest error and keep watching.
console.log( `[PHP Recovery - ${ id }] Retry failed, still watching...` );
const pm2Logs = readPm2Logs( id );
const logContent = [ ...( pm2Logs.stdout ?? [] ), ...( pm2Logs.stderr ?? [] ) ].join(
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ayground-fix # Conflicts: # apps/cli/package.json # apps/studio/package.json # package-lock.json
…' into gcsecsey/stu-1370-php-error-recovery # Conflicts: # apps/studio/package.json # package-lock.json
Collaborator
📊 Performance Test ResultsComparing c6d6380 vs trunk app-size
site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issues
runCLI()throws instead of callingprocess.exit().How AI was used in this PR
I used Claude to port the PHP-error recovery from an earlier branch onto the current trunk, wire it into the start and stop handlers, and add unit tests for the error classification and parsing. I reviewed the logic and verified typecheck, build, and the tests myself.
Proposed Changes
When a site has a fatal PHP error (for example in a theme or a mu-plugin), starting it should not just fail. The site should come up and show the error, the way the native PHP runtime already does.
For the Playground (WASM) runtime, this cannot be done the native way. Playground warm-boots WordPress at startup, so a fatal error aborts the boot and the server never comes up, which means there is no live WordPress to render its own error page. This PR adds a Studio-side recovery that fills that gap:
.phpfile changes, so fixing the error auto-recovers the site.Testing Instructions
npm installnpm startCase 1 (error at start)
wp-content/mu-plugins/fatal.phpfile in the site folder and add:fatal.php.Case 2 (running site, error at runtime)
.phpfile and reload the site in the browser.