2

TLDR:

What is this arbitrary RegExp execution time limit, how long is it, and when does it apply (because it does not apply equally in all Google Apps Script contexts)? Also, why does it apply when there are already execution time limits for the entire script?

Full Post:

I have suddenly hit the error

"Error: Regular expression operation exceeded execution time limit."

in Google Apps Script. I have hit this error while running a function using a custom menu on Google sheets that I created. This makes a brief UI which requests the use to input a spreadsheet url, and then runs a function using the provided url (and spreadsheet).

I have run this function before and it worked fine, but now I am getting this regular expression time limit error. To be clear this script comes nowhere near the maximum time limit for script execution, it is only apparently that my regular expression is too long. I have determined the line with the regular expression (which runs repeatedly and is usually fine and has worked up to this point) has no obvious flaws. It is a large regular expression, but the text is not very long. It failed on a 217 character text.

Furthermore, I have discovered that the error does NOT occur, when I run the function equivalent from the Google Apps Script Editor (without the UI, which simply calls this same function from a Google Apps Script Library I created). To be clear I am certain that the variables and environment in the working execution are the same. It completed in 8 seconds, parsed the same text, and used the same regular expression.

This leads me to believe that there is an arbitrary time limit that is applied to regular expressions which applies either because the function has been called from a custom menu, the function briefly uses UI, or the function calls a library (or some combination of these).

What is this arbitrary RegExp execution time limit, how long is it, and when does it apply (because it does not apply equally in all Google Apps Script contexts)? Also, why does it apply when there are already execution time limits for the entire script?

I haven't been able to find anything mentioning this specific error/time limit/quota on Google's documentation of Google Apps Script.

To be clear, I have checked that they are using the UI script is using the correct library version (and development mode is on anyway, so it is using the most up to date version). I have also confirmed that same functions are running with the same variables via console printing so I know the only difference is how the function is being called.

Here is the RegExp that breaks the time limit in one context but no the other, if you need it for some reason:

/[\s\<\>]*\d+\s*(?:(?:l\s*f|linear\s*feet|lin\s*feet|lin\s*ft)|(?:s\s*f|square\s*feet|sq\s*\ft|sq\s*feet|sq)|(?:ea|each))(?:[\s\,]*\S+){0,7}\s*\,\s*(?:(?:(?:(?:remove|removal|(?:(?:^|\s)+rem(?:\s|\.|\:|\-|$))|(?:(?:^|\s)+rmv(?:\s|\.|\:|\-|$))))|(?:(?:encapsulate|encapsulation|(?:^|\s)+encp?(?:ap)?(?:$|\s|\.|\-|\:)+|(?:^|\s)+cap(?:$|\s|\.|\-|\:)+|(?:^|\s)+enp(?:$|\s|\.|\-|\:)+|(?:^|\s)+seal(?:$|\s|\.|\-|\:)+))|(?:enclose)))/gi

MCVE:

Here is some text it failed on in one context but not in another:

Storage and Mechanical Room 6 adjacent to Stage- 6 month AHERA 15 EA ACPFI RMV <Category: 3> Note: Middle of ceiling, 5 damaged fittings. RMV all. 0 SF Fireproofing, Enclosure, Above ceiling tiles <Category: 3> See note

To reproduce the failing context, in a Google Sheets Spreadsheet, create a custom menu using the script editor (as a document bound script), and click the "Test" button.

Container-bound Script Code:

function onOpen(e) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Test Menu').addItem('Test', 'testFun').addToUi();
}

function testFun() {
  var regExp = /[\s\<\>]*\d+\s*(?:(?:l\s*f|linear\s*feet|lin\s*feet|lin\s*ft)|(?:s\s*f|square\s*feet|sq\s*\ft|sq\s*feet|sq)|(?:ea|each))(?:[\s\,]*\S+){0,7}\s*\,\s*(?:(?:(?:(?:remove|removal|(?:(?:^|\s)+rem(?:\s|\.|\:|\-|$))|(?:(?:^|\s)+rmv(?:\s|\.|\:|\-|$))))|(?:(?:encapsulate|encapsulation|(?:^|\s)+encp?(?:ap)?(?:$|\s|\.|\-|\:)+|(?:^|\s)+cap(?:$|\s|\.|\-|\:)+|(?:^|\s)+enp(?:$|\s|\.|\-|\:)+|(?:^|\s)+seal(?:$|\s|\.|\-|\:)+))|(?:enclose)))/gi;
  var text = 'Storage and Mechanical Room 6 adjacent to Stage- 6 month AHERA 15 EA ACPFI RMV <Category: 3> Note: Middle of ceiling, 5 damaged fittings. RMV all. 0 SF Fireproofing, Enclosure, Above ceiling tiles <Category: 3> See note';
  text.match(regExp);
  Logger.log('This line will not be reached because of error');
}

It also fails when running testFun() from the container-bound script in the script editor.

To reproduce the successful execution context, create a standalone google apps script (not from the spreadsheet) and run testFun() in the script editor.

Standalone Script Code:

function testFun() {
  var regExp = /[\s\<\>]*\d+\s*(?:(?:l\s*f|linear\s*feet|lin\s*feet|lin\s*ft)|(?:s\s*f|square\s*feet|sq\s*\ft|sq\s*feet|sq)|(?:ea|each))(?:[\s\,]*\S+){0,7}\s*\,\s*(?:(?:(?:(?:remove|removal|(?:(?:^|\s)+rem(?:\s|\.|\:|\-|$))|(?:(?:^|\s)+rmv(?:\s|\.|\:|\-|$))))|(?:(?:encapsulate|encapsulation|(?:^|\s)+encp?(?:ap)?(?:$|\s|\.|\-|\:)+|(?:^|\s)+cap(?:$|\s|\.|\-|\:)+|(?:^|\s)+enp(?:$|\s|\.|\-|\:)+|(?:^|\s)+seal(?:$|\s|\.|\-|\:)+))|(?:enclose)))/gi;
  var text = 'Storage and Mechanical Room 6 adjacent to Stage- 6 month AHERA 15 EA ACPFI RMV <Category: 3> Note: Middle of ceiling, 5 damaged fittings. RMV all. 0 SF Fireproofing, Enclosure, Above ceiling tiles <Category: 3> See note';
  text.match(regExp);
  Logger.log('This line will be successfully reached');
}
TheMaster
  • 45,448
  • 6
  • 62
  • 85
  • I also got this message, and I just converted the method into a function that was used against each separate cell. If you get the error message when running against a single cell value, it is a catastrophic backtracking signal. – Wiktor Stribiżew Sep 22 '20 at 18:24
  • @WiktorStribiżew It's absolutely a RegEx that I could clean up, or separate into smaller parts and separate the parsing, but at this point, I'm actually more questioning why the RegEx time limit exists at all and why it applies in one context but not in the other (since it does work in a different execution context - running it from the apps script editor) – Austin Gwiazdowski Sep 22 '20 at 18:34
  • 1
    @AustinGwiazdowski Could you [edit] to provide sample text, where it fails, for others to reproduce the error in different contexts. – TheMaster Sep 22 '20 at 18:56
  • Only Google can answer why the RegEx time limit exists. If this is what you actually are asking then the question off-topic. – Rubén Sep 22 '20 at 19:32
  • 1
    @TheMaster Added at the bottom. – Austin Gwiazdowski Sep 22 '20 at 20:59
  • 1
    @Rubén The question is how long is the time limit, and in what execution contexts does it apply. The "why" part of the question is for if anyone can give extra context/info that might help avoid these situations in the future. I also don't know if only Google can answer that question, because someone else may have been able to find documentation on the subject that I couldn't, or someone else might have expertise in regular expressions or google Apps execution contexts that would help answer the "how long" and "where" questions. – Austin Gwiazdowski Sep 22 '20 at 21:16

1 Answers1

3

Partial answer:

  • The issue is reproducible in engine.
  • The issue doesn't seem to be reproducible in engine

This seems to account for differences in execution context. Given the deprecation of engine, It's unlikely that you find the exact limit or reason of the issue(But it seems to be around 300ms).

TheMaster
  • 45,448
  • 6
  • 62
  • 85
  • 1
    The failing script was run on the older engine because I did not realize it was an older container-bound script. I have since switched the engine and have not had the error, so this eliminates the need to understand it (and any need for future understanding). Thank you! – Austin Gwiazdowski Sep 22 '20 at 21:29