Troubleshooting New Relic's "maximum PHP function nesting level" error

When analyzing your site's logs to investigate "temporarily unavailable" errors on your Acquia Cloud site, you may encounter an error message like the one below in your php-errors.log:

PHP Fatal error: Aborting! The New Relic imposed maximum PHP function nesting level of '5000' has been reached. This limit is to prevent the PHP execution from catastrophically running out of C-stack frames. If you think this limit is too small, adjust the value of the setting newrelic.special.max_nesting_level in the newrelic.ini file, and restart php. Please file a ticket at https://support.newrelic.com if you need further assistance in /path/to/file.php on line 1

The message above is triggered by the New Relic PHP extension running on your servers when a PHP script on your site attempts to make more than 5,000 recursive function calls. This occurs when the script in question executes a PHP function defined in your site's code (let's call it "Function A", but Function A requires that your script attempt to execute another function (let's call it Function B) before Function A can complete its execution. This concept of "nesting" PHP function calls within the body of other PHP functions is called recursion, and is a common (and often useful) practice when writing PHP code. 

However, this process of executing a function "within" another PHP function becomes problematic when a PHP script recurses too deeply into a series of nested function calls. Since PHP requires server memory for each function call it makes, and since that memory can't be released until the function that's using it has finished executing, the execution of too many PHP functions recursively can result in a stack overflow, in which the PHP process executing the script runs out of space to store any more information about the functions it's attempting to execute. Unless mitigating measures are taken, this situation quickly leads to a more severe problem, called a segmentation fault (or segfault), in which your server's operating system will intervene to prevent the PHP process running this script from accessing memory resources that are meant for other programs on the server. This intervention results in the termination of this PHP process, and a fatal (HTTP 500) error for any web requests that it was attempting to respond to at the time of the segfault.

Due to the severity of this stack overflow situation, and its potential impact on your server's performance if it occurs regularly, some monitoring and debugging extensions for PHP (like New Relic or XDebug) provide a feature that allows them to mitigate these PHP recursion issues, triggering a PHP fatal error that halts execution of the recursive script, before the operating system is forced to step in and terminate the PHP process altogether.

In short, the New Relic error you're seeing in your logs is the result of a safeguard protecting your web server's performance. For this reason, we recommend against attempting to suppress it by increasing the value of the newrelic.special.max_nesting_level PHP INI variable. Unlike errors involving PHP's memory limit or max input variables, errors of this nature are often caused by application logic problems that won't be corrected by simply relaxing the limit imposed by one of PHP's configuration variables.

Instead, we recommend using the information in this error message, specifically the file and line number mentioned at the end, to diagnose and address potential logic issues in your site's code or configuration. In all but the very rarest of cases, these errors are triggered by an infinite recursion problem, in which Function A requires the execution of Function B, and Function B requires the execution of Function A so that, when PHP attempts to execute the script containing Functions A and B, it enters a recursive loop of alternating calls to these two functions, which is only finally broken by the "function nesting limit" error mentioned above. Logic problems involving these recursive function loops usually involve more than just two functions, and the sequence of recursive function calls leading up to one of these errors can often be used to determine what the PHP script is trying to accomplish, and the potential locations in your site's codebase that need to be inspected for logic errors. This sequence of function calls, known as a stack trace, can be obtained in a couple of different ways:

Use New Relic's Error Trace feature to obtain a stack trace

One important aspect of New Relic's recursion protection feature is that it automatically records a stack trace of the function calls leading up to one of these errors. If you have access to New Relic's application monitoring dashboard for your site, you can use the time and text associated with these error messages to locate their stack trace information using the "Error Trace" section of New Relic's Error Analytics page.

If you don't have access to New Relic, but are seeing this error on one of your Acquia Cloud Enterprise or Acquia Cloud Site Factory sites, our support team will be happy to help you track down the stack trace information you're looking for. Just file a new support ticket, and include the full text of the error message you're seeing, including the date and time, in your report.

Use another debugging tools with a recursion protection feature

If you don't have access to a New Relic stack trace, you might consider using another PHP debugging tool that supports recursion detection and protection, like XDebug, to generate a stack trace during a subsequent reproduction of the error. You can find more information about setting up and using XDebug in your local development environment in our article on configuring Xdebug with PHPStorm.

Insert debugging code to generate a PHP stack trace

If you don't have access to any of the tools discussed above, you'll need to capture some information about this error on your own by inserting debugging code that attempts to monitor PHP's recursion depth, and generates a stack trace once a a certain number of recursive calls has been reached. The following code is designed to be inserted temporarily in your site's codebase, surrounding the line of code mentioned in New Relic's error message (this line of code will contain a PHP function call), and will attempt to detect a recursive loop of function calls using a static counter variable that is incremented each time the code is executed recursively. After a set number of recursive calls (which can be configured by modifying the $recursion_limit variable in this code, PHP will print a stack trace, and immediately stop executing the current script:

// Modify this variable to change the number of recursive calls to the function containing this code that will be allowed before PHP prints a stack trace and exits the current script.
$recursion_limit = 5;

static $recursion_counter = 0;
$recursion_counter++;
if ($recursion_counter < $recursion_limit) {

  // Execute the recursive function call mentioned in your New Relic error here.

} 
else {
  debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  exit;
}
$recursion_counter--;

The code above is not designed to provide a safeguard against these errors, or to prevent them from occurring altogether, but rather simply to provide the stack trace that may reveal a pattern of function calls that indicates a recursive loop. As mentioned above, you may need to modify the value of that $recursion_limit in order to produce the level of stack trace information required to reveal such a pattern. For more information and suggestions concerning this sort of debugging technique, please see our article on debugging using debug_backtrace.

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.

Contact supportStill need assistance? Contact Acquia Support