WP Debug Toolkit 1.2.0 is LIVE. Get $300 discount on the lifetime deal now
Use Discount Code WPDTLTD

WP Debug Toolkit (WPDT) applies rate limiting per WordPress error signature and enforces a global hourly cap so a single crashing plugin cannot flood your inbox. Every alert WPDT evaluates, including suppressed ones, is recorded in the Notification History panel at the bottom of WP Debug Toolkit › Settings › Notifications, giving you a complete audit trail of what fired, what was suppressed, and why. The history log retains entries for seven days.

In This Guide

What Is Rate Limiting and Alert History

Rate limiting is the system WPDT uses to control how frequently the Email Notifier sends email notifications. 

It operates at two levels: a per-error cooldown that governs how soon the same error can trigger a second alert, and a global max emails per hour cap that sets a ceiling on recorded sent entries in any 60-minute window

Without this system, a single recurring fatal error on a live site can generate dozens of identical emails within minutes, especially under traffic. WPDT’s rate limiter prevents that while still recording every event it evaluates. When an alert is suppressed, WPDT writes it to the Notification History log with a status that tells you exactly why it was not sent. Your inbox stays manageable, and the audit trail stays complete.

How It Works

WPDT first normalizes every qualifying error, then performs rate-limiting checks before sending a notification. The order of those checks differs by error type: for fatal errors, the global hourly cap is evaluated before the per-error cooldown; for non-fatal errors, the per-error cooldown is evaluated first. This distinction determines which suppression status, either skipped_duplicate or skipped_global_rate_limit, gets recorded in Notification History when both limits would apply to the same event.

How WPDT Builds an Error Signature

Before the rate limiter applies any cooldown, WPDT normalizes the raw error message. Stack traces and stack frame lines are stripped entirely. 

For memory exhaustion errors, everything inside parentheses is removed. File paths inside parentheses are stripped from all error messages regardless of type. The normalized message, combined with the PHP error type, source file path, and line number, is then MD5-hashed to produce a stable error signature.

php
// Example: three OOM crashes produce three different raw messages
"Allowed memory size of 134217728 bytes exhausted (tried to allocate 4096 bytes)"
"Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes)"
"Allowed memory size of 134217728 bytes exhausted (tried to allocate 16384 bytes)"

// WPDT strips the parenthetical allocation value before hashing.
// All three normalize to the same signature -- one cooldown window, one alert.
// Normalized: "Allowed memory size of 134217728 bytes exhausted"

// Note: file path and line number are also part of the hash.
// The same error moved to a different line number generates a new signature.

This normalization means that a plugin triggering repeated out-of-memory crashes with different allocation sizes counts as one error signature and not three. 

The rate limiter applies per signature, so suppression behaves consistently across all instances of the same underlying error from the same source location.

How the Per-Error Cooldown Works

After WPDT sends a notification for an error signature, it sets a cooldown that blocks re-alerts for that same signature. That cooldown duration is fixed by error type and is not affected by the Per-Error Cooldown setting: fatal errors carry a one-hour cooldown; non-fatal errors (warnings, notices, deprecated) carry a 24-hour cooldown. 

Recurring instances of the same error within the active cooldown are suppressed and recorded in Notification History with the status skipped_duplicate.

The Per-Error Cooldown setting controls something separate: concurrent-request deduplication. When a crash affects multiple visitors simultaneously, many PHP processes may attempt to fire the same alert in the same instant. WPDT uses the Per-Error Cooldown value to define a claiming window, which is the period during which only one process can claim an error signature for notification. Every other process recognizes the existing claim, skips the send, and records the event as suppressed. 

Available presets are 15min, 30min, 1hr, 6hr, 12hr, and 24hr.

How the Global Hourly Cap Works

Max Emails Per Hour is a hard ceiling on the total number of recorded sent entries WPDT logs in any 60-minute window. For fatal errors, one entry equals one email, and the ceiling is user-configurable. For non-fatal errors, WPDT may combine multiple error signatures into a single email, but each signature is recorded as a separate sent entry and counts toward the cap individually; the ceiling is fixed at five per hour regardless of this setting.

The cap exists to handle scenarios where many distinct error signatures each pass their individual cooldowns, but together would still generate an inbox flood. 

When the cap is reached, WPDT records suppressed alerts in the Notification History with the status skipped_global_rate_limit. Available presets are 5, 10, 20, 50, and 100. The field accepts any value between 1 and 100.

Race-Condition Protection

When a crash affects multiple simultaneous visitors, multiple PHP processes can attempt to fire the same alert at the same moment. WPDT prevents this with two coordinated mechanisms: a WordPress database INSERT IGNORE to atomically claim the error for a single process, and flock() file locking as a fallback when the database is unavailable. 

The locking system ensures that only one alert fires per error signature per rate-limit window, even under 50 concurrent requests. Every other process recognizes the existing claim and records the event as suppressed rather than firing its own notification.

Key Guarantees

  • WPDT records every alert it evaluates with suppressed alerts appearing in the Notification History log with a status of skipped_duplicate or skipped_global_rate_limit, so the log reflects the complete event picture, not only what reached your inbox.
  • The cooldown window applies per error signature, not per raw error message, so normalization ensures that multiple crash instances from the same source location and error type share a single suppression window.
  • Max Emails Per Hour applies to all fatal error alerts combined; non-fatal alerts have a separate fixed ceiling of five per hour which ensures that critical fatals always have headroom.
  • The locking system ensures only one alert fires per error signature per rate-limit window, even under 50 concurrent requests.

Key Concepts

Term / Constant / FileWhat It Means
Rate limit windowThe time period during which WPDT suppresses repeat alerts for a given error signature. The duration is set internally by error type: one hour for fatal errors, 24 hours for warnings and all non-fatal types. The window resets after it expires, allowing the next occurrence to trigger a fresh notification.
Error signatureAn MD5 hash generated from the normalized error message, PHP error type, source file path, and line number. Two crashes with different allocation sizes but the same source location share one signature. The same error, moved to a different line number, gets a new signature.
7-day history storeA fixed rolling window. WPDT retains notification history entries for seven days and caps the store at 1,000 entries. The window is not user-configurable. Entries older than seven days are pruned automatically.
notification-history.phpThe file WPDT writes the notification history to, stored at wp-content/debug-toolkit/notification-history.php. Protected from direct HTTP access by a PHP die guard at the top of the file.
Per-Error CooldownThe setting that controls the concurrent-request claiming window: how long WPDT holds an exclusive claim on an error signature so that only one PHP process fires the alert when the same crash affects multiple simultaneous visitors. The re-alert interval between notifications is set internally by error type and is not affected by this value. Presets: 15min, 30min, 1hr, 6hr, 12hr, 24hr.
Max Emails Per HourThe hard ceiling on recorded sent entries logged in any 60-minute window. For fatal errors, one entry equals one email and the ceiling is user-configurable. For non-fatal errors, the ceiling is fixed at five entries per hour; multiple signatures may be combined into a single email, so the entry count and email count can differ. Presets: 5, 10, 20, 50, 100.
Smart Message DeduplicationThe normalization step that strips stack traces, stack frame lines, memory allocation values, and file paths from error messages before hashing. This runs before the rate limiter, ensuring the cooldown window applies to the logical error rather than the literal message text.
History entry statusEach Notification History entry carries one of three status values: sent (the alert was delivered), skipped_duplicate (suppressed because the error signature’s cooldown window was active), or skipped_global_rate_limit (suppressed because Max Emails Per Hour was reached).

Configuration

Both rate-limiting thresholds are user-configurable. Navigate to WP Debug Toolkit › Settings › Notifications and open the Rate Limiting accordion to adjust either setting.

Step 1: Set the Per-Error Cooldown. Select one of the preset buttons: 15min, 30min, 1hr, 6hr, 12hr, or 24hr, or type a custom value in seconds into the field. This controls the concurrent-request claiming window, which is how long WPDT holds an exclusive claim on an error signature so that only one PHP process fires the alert when the same crash affects multiple simultaneous visitors. 

The re-alert interval between notifications for the same error is set internally by error type: one hour for fatal errors, 24 hours for non-fatal errors, and is not affected by this value.

Step 2: Set Max Emails Per Hour. Select one of the preset buttons; 5, 10, 20, 50, or 100, or enter a custom value between 1 and 100. You should lower this value if alert volume remains difficult to manage.

Step 3: Save your settings. Click Save Settings to apply both changes.

wp-debug-toolkit-rate-limiting-configuration-settings

Common Issues and How to Fix Them

Alert History Shows No Entries Even Though Errors Are Occurring

Likely cause: Email notifications are disabled, or the MU-plugin (wpdebugtoolkit-notifications.php) is not installed, so WPDT is not evaluating errors for alerting and has nothing to record.

Fix: Navigate to WP Debug Toolkit › Settings › Notifications and confirm that the Email Notifications toggle is enabled and at least one error level is selected. If notifications appear enabled but the history remains empty, check the Must-Use Plugin section on the same page. If the status shows Not Installed (Optional), click Install MU-Plugin to install it. WPDT installs wpdebugtoolkit-notifications.php automatically in wp-content/mu-plugins/ when the MU-plugin is activated.

Still Receiving Too Many Notifications After Configuring Rate Limits

Likely cause: Multiple distinct error signatures from the same plugin are each passing their individual cooldowns, so each one generates its own alert even though they all originate from the same source.

Fix: Check the Notification History panel to see which error signatures are firing most frequently. Look at the error_type_string and file fields in recent entries to identify the pattern. If many different signatures are active, lower Max Emails Per Hour. Navigate to WP Debug Toolkit › Settings › Notifications › Rate Limiting to adjust it.

Frequently Asked Questions

Does WPDT still record an alert if it was suppressed by rate limiting?

Yes. WPDT records every alert it evaluates, regardless of whether the notification was sent. Suppressed alerts appear in the Notification History panel with a status of skipped_duplicate (suppressed because the error signature’s cooldown window was active) or skipped_global_rate_limit (suppressed because the hourly cap was reached). The log gives you the complete picture of what occurred on your site, and not only what reached your inbox.

How do I know if a critical error was suppressed and not sent?

Go to the Notification History panel at the bottom of WP Debug Toolkit › Settings › Notifications. Each entry includes the error type, message, file, line number, timestamp, and status. An entry with status skipped_duplicate was suppressed because the same error signature fired again while its cooldown window was still active. An entry with status skipped_global_rate_limit was suppressed because Max Emails Per Hour was already reached for that hour.

Why did I receive multiple notifications for what looks like the same error?

Two errors can appear similar in your inbox but carry different error signatures if they originate from different source files or line numbers. WPDT’s error signature includes the file path and line number as well as the normalized message. If the same logical error appears in two locations in your codebase, WPDT generates two distinct signatures with independent cooldown windows. Check the file and line fields in the Notification History entries to confirm whether the alerts came from the same source location or different ones.

Related Documentation

Email Notifications Overview – Understand how the MU-plugin, emergency memory protection, and Smart Message Deduplication work together as a system.

Setting Up Notifications – Go here to adjust the Per-Error Cooldown and Max Emails Per Hour thresholds covered in this article. Two settings, one screen.

Out of Memory Errors – See how repeated OOM crashes from the same source normalize to a single error signature, so a plugin leaking memory dozens of times per minute sends one alert, not dozens

On this page
Try WP Debug Toolkit
The best error log viewer with amazing developer tools to help you troubleshoot your WordPress site securely and efficiently. Something something more.