Seemingly simple patterns can cause `string.match()` to throw timeout errors near end of time slice
planned
LiamHoffen Resident
Running on server: Luau 2026-01-06.20757451310
In successive calls of string.match, I often get a fatal error if I don't wrap string.match in a pcall:
runtime error
lua_script:3: String pattern too complex, timed out
[C] function match
The problem is that the only thing repeatable is that I may or may not get errors when running the code.
local function getStringMatch(s)
local status, k, v
repeat
status, k, v = pcall(string.match, s, "(%g+)%s*=%s*(%g+)")
if not status then print(k) end
until status
end
local keys = {}
for i = 1, 10 do
table.insert(keys, tostring(ll.GenerateKey()))
end
for k, v in keys do
print(k)
getStringMatch(v)
end
This is basically a useless example, except to trigger the issue. gmatch should return the captures, the original string if no captures, or nil.
This example will never find a match, but I don't believe string complexity is the issue, and I don't believe its timing out because it happens very fast.
But, if a failure is triggered, I can recall the very same match again and get success, without providing any delays in the code.
Log In
H
Harold Linden
marked this post as
planned
Thanks for the report! Yeah, that's an unfortunate conflict with how Lua in general (and Luau specifically) implements the pattern matching, and how we need apply limits for how long a script can run.
Likely we need to write a custom implementation that allows yielding inside
string.match()
itself.Tapple Gao
There's another regex parser in the simulators: the one that implements llLinksetDataFindKeys. Dunno if it has the same issue. If not, could use that one instead. I don't see a technical reason SLua needs to be compatable with Luau, only a political reason (to make updates and documentation easier)
I dunno if the regex syntax of llLinksetDataFindKeys should change to match the syntax of string.match, or vice-versa. They don't use the same syntax.
H
Harold Linden
Tapple Gao:
string.find()
provides a Lua (not Luau)-specific pattern matching and is used in most non-trivial Lua scripts that do data munging.There doesn't seem to be a lot of prior on optimizing Lua pattern matching behavior, but I think a lot of these are simple enough that it's straightforward to compile them to re2 expressions, and use re2 under the hood. That would allow us to provide APIs for proper regex support everywhere as well.
That being said, I don't like that
string.find()
and friends can't yield internally if they run too long, but the design of conventional Lua pattern matching implementations doesn't allow for it. It's on my TODO list to rewrite the pattern matching code inherited from Luau to support that, but it's very tricky work.SuzannaLinn Resident
Pattern matching is slow. Depending on when it starts within the script's assigned time slice, it might not have enough time to finish, causing an error.
More details in a previous canny: https://feedback.secondlife.com/slua-alpha/p/stringmatch-can-trigger-unable-to-perform-mandatory-yield-error
The workaround is to add a sleep before the operation. This waits until the next frame, ensuring the full time slice is available to execute the function:
local function getStringMatch(s)
local status, k, v
repeat
ll.Sleep(0.00001)
status, k, v = pcall(string.match, s, "(%g+)%s*=%s*(%g+)")
if not status then print(k) end
until status
end