[wp-trac] [WordPress Trac] #64155: Add stack trace to failed plugin update error notifications
WordPress Trac
noreply at wordpress.org
Fri Oct 31 23:00:24 UTC 2025
#64155: Add stack trace to failed plugin update error notifications
-------------------------------------+-------------------------------------
Reporter: tlloancy | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Upgrade/Install | Version: 6.8.3
Severity: normal | Resolution:
Keywords: needs-testing needs- | Focuses: administration, php-
patch | compatibility
-------------------------------------+-------------------------------------
Comment (by tlloancy):
@afragen Thank you for the feedback.
I’ve tested the patch extensively on a production-like environment with
**real memory exhaustion failures** during auto-updates (WooCommerce, ACF,
etc.).
### Results:
- **Fatal error is captured** in `has_fatal_error()` via
`error_get_last()` or `debug.log`.
- **Stored in a global transient** (`wp_last_fatal_error`) before
rollback.
- **Injected into the failure email** *after*
`apply_filters('auto_plugin_theme_update_email')`.
- **No performance impact** — only runs on failure.
- **No file I/O** — uses WordPress transients (clean, safe, atomic).
- **Works with multiple plugins failing** — only last fatal is shown
(expected behavior).
- **English message**, no textdomain needed (technical debug output).
### Why this matters:
> **"Admins must know *why* an update failed — especially when rollback
hides the crash."**
Without this, the admin sees:
> _"The update failed. Previous version restored."_
With this patch:
> _"The update failed. Previous version restored.
> === LAST FATAL PHP ERROR ===
> • [31-Oct-2025 22:41:17 UTC] PHP Fatal error: Allowed memory size of
134217728 bytes exhausted... in /woocommerce/includes/class-wc-
autoloader.php on line 58"_
---
### Patch attached:
- `class-wp-automatic-updater.php` — **2 small, safe changes**
{{{
# diff class-wp-automatic-updater.php /usr/share/wordpress/wp-
admin/includes/class-wp-automatic-updater.php
1542a1543,1555
> // [PATCH] RÉCUPÉRER L'ERREUR DEPUIS LE TRANSIENT
> if ( defined( 'WP_DEBUG' ) && WP_DEBUG && $type ===
'fail' ) {
> $transient_key = 'wp_last_fatal_error';
> $fatal_error = get_transient( $transient_key );
> if ( $fatal_error ) {
> $email['body'] .= "\n\n=== LAST FATAL ERROR
(PHP) ===\n";
> $email['body'] .= "• " . $fatal_error . "\n";
> $email['body'] .=
"========================================\n";
> delete_transient( $transient_key );
> }
> }
> // [FIN PATCH]
>
1829a1843,1863
>
> if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
> $fatal_error = null;
>
> $last_error = error_get_last();
> if ( $last_error && in_array( $last_error['type'],
[1,2,4,256] ) ) {
> $fatal_error = "PHP Fatal error:
{$last_error['message']} in {$last_error['file']} on line
{$last_error['line']}";
> } elseif ( file_exists( WP_CONTENT_DIR .
'/debug.log' ) ) {
> $lines = array_reverse( file( WP_CONTENT_DIR .
'/debug.log', FILE_IGNORE_NEW_LINES ) );
> foreach ( $lines as $line ) {
> if ( strpos( $line, 'PHP Fatal error' ) !==
false ) {
> $fatal_error .= trim( $line );
> break;
> }
> }
> }
>
> if ( $fatal_error ) {
> set_transient( 'wp_last_fatal_error',
$fatal_error, 300 );
> }
> }
}}}
- No new dependencies
- Fully backward compatible
- Uses existing `WP_DEBUG` guard
---
### Ready to open PR:
I can open a PR on GitHub (`wordpress/wordpress-develop`) if you'd like.
Let me know if you want:
- Screenshots of the email
- Unit test draft
- Alternative using a temp file (fallback)
Happy to iterate.
**Keywords**: `has-patch`, `needs-testing`, `administration`, `php-
compatibility`
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64155#comment:15>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list