mongodb/laravel-mongodb · error · LogicException
Missing expected starting delimiter in regular expression
Error message
Missing expected starting delimiter in regular expression "%s", supported delimiters are: %s
What it means
When compiling a 'regex'/'not regex' where clause, a string pattern must be a preg-style pattern with a leading delimiter (e.g. /pattern/i). The library checks the first character against its supported delimiter list and throws LogicException if it isn't one, because it cannot parse flags or the pattern body otherwise.
Solutions
- Wrap the pattern in delimiters: ->where('name', 'regex', '/^abc$/i').
- Choose a supported delimiter character as the first char (e.g. / or ~) matching self::REGEX_DELIMITERS.
- If the value may already contain delimiters, detect and only wrap when substr($pattern, 0, 1) is not a delimiter.
- Precompile to a MongoDB\BSON\Regex object to bypass string parsing: ->where('name', 'regex', new Regex('^abc$', 'i')).
Example fix
// before
$query->where('name', 'regex', '^abc');
// after
$query->where('name', 'regex', '/^abc/i'); Defensive patterns
Strategy: validation
Validate before calling
if (is_string($pattern) && !in_array(substr($pattern, 0, 1), ['/', '#', '~'], true)) {
$pattern = '/' . trim($pattern, '/') . '/';
} Prevention
- Always wrap user patterns in delimiters.
- Prefer BSON Regex objects over strings.
- Centralize regex-where construction in one helper.
When it happens
Trigger: ->where('name', 'regex', '^abc$') (no / delimiters); passing a Mongo shell-style BSON regex string without delimiters; building the regex from concatenation that loses the leading delimiter; REGEX_DELIMITERS mismatch such as using # or unsupported chars.
Common situations: Copy-pasting patterns from Mongo shell or regex101 (which use bare patterns or different delimiters); user-supplied search strings wrapped in code not delimiters.
Related errors
- Missing expected ending delimiter
- Between $values must be a list with exactly two elements…
- 2nd argument of () must be "null" when 1st argument is an…
- Distinct queries cannot be used for pagination. Use GroupBy…
- The value used as a document id or relation key cannot…
AI-assisted analysis of mongodb/laravel-mongodb@0634653039 (2026-09-15).
Data as JSON: /api/errors/4e3eb26ca3b8b21f.
Report an issue: GitHub.
Appendix: source
Thrown at src/Query/Builder.php:1510
// All backslashes are converted to \\, which are needed in matching regexes.
preg_quote($value),
);
$flags = $where['caseSensitive'] ?? false ? '' : 'i';
$value = new Regex('^' . $regex . '$', $flags);
// For inverse like operations, we can just use the $not operator with the Regex
$operator = $operator === 'like' ? '=' : 'not';
// phpcs:ignore Squiz.ControlStructures.ControlSignature.SpaceAfterCloseBrace
}
// Manipulate regex operations.
elseif (in_array($operator, ['regex', 'not regex'])) {
// Automatically convert regular expression strings to Regex objects.
if (is_string($value)) {
// Detect the delimiter and validate the preg pattern
$delimiter = substr($value, 0, 1);
if (! in_array($delimiter, self::REGEX_DELIMITERS)) {
throw new LogicException(sprintf('Missing expected starting delimiter in regular expression "%s", supported delimiters are: %s', $value, implode(' ', self::REGEX_DELIMITERS)));
}
$e = explode($delimiter, $value);
// We don't try to detect if the last delimiter is escaped. This would be an invalid regex.
if (count($e) < 3) {
throw new LogicException(sprintf('Missing expected ending delimiter "%s" in regular expression "%s"', $delimiter, $value));
}
// Flags are after the last delimiter
$flags = end($e);
// Extract the regex string between the delimiters
$regstr = substr($value, 1, -1 - strlen($flags));
$value = new Regex($regstr, $flags);
}
// For inverse regex operations, we can just use the $not operator with the Regex
$operator = $operator === 'regex' ? '=' : 'not';
}View on GitHub (pinned to 0634653039)