The Error
PHP Warning: preg_match(): No ending delimiter '/' found in /var/www/html/app.php on line 23
PHP throws this the moment it tries to compile your regex and can't locate the closing delimiter. preg_match() returns false instead of 0 or 1 โ so any if-check downstream silently misbehaves without you realizing the pattern never ran.
Why It Happens
PHP's PCRE functions (preg_match, preg_replace, preg_split, etc.) require a delimiter character wrapped around the pattern. Forward slash is the conventional choice:
/your-pattern-here/flags
Four things trigger this warning:
- The closing delimiter is missing entirely
- The delimiter character appears unescaped inside the pattern itself
- A plain string was passed instead of a proper regex (e.g.,
"email"instead of"/email/") - The pattern was built dynamically and string concatenation dropped the closing delimiter
Step-by-Step Fix
1. Add the Missing Closing Delimiter
The most frequent cause โ someone wrote the opening slash and forgot the closing one:
<?php
// Broken
preg_match('/^[a-z]+', $input);
// Fixed
preg_match('/^[a-z]+/', $input);
2. Escape the Delimiter Inside the Pattern
URL patterns are the classic trap. Your pattern contains / characters, PHP reads the first one as the closing delimiter, and everything after it becomes garbage:
<?php
// Broken โ the / in the URL closes the regex right after 'https:'
preg_match('/https://example.com/', $url);
// Option A โ escape the delimiter
preg_match('/https:\/\/example\.com/', $url);
// Option B โ switch delimiters (much cleaner for URLs)
preg_match('#https://example\.com#', $url);
PHP accepts any non-alphanumeric, non-backslash, non-whitespace character as a delimiter: /, #, ~, !, |, and even matching bracket pairs like {} or (). For patterns involving URLs or file paths, # saves you from escaping every slash.
3. Fix Dynamically Built Patterns
Dynamic patterns are the sneakiest source of this bug. Say you're building a keyword search filter from user input:
<?php
$keyword = 'error';
// Broken โ missing the opening delimiter entirely
$pattern = $keyword . '/i';
preg_match($pattern, $log);
// Fixed
$pattern = '/' . preg_quote($keyword, '/') . '/i';
preg_match($pattern, $log);
Always wrap variable content with preg_quote(). It escapes every special regex character โ including your chosen delimiter โ so injected values can't break the pattern structure.
4. Check for Accidental Plain Strings
No delimiters at all is another common slip, especially when migrating old code from ereg() (deprecated in PHP 5.3, removed in PHP 7):
<?php
// Broken โ no delimiters at all
preg_match('email', $input);
// Fixed
preg_match('/email/i', $input);
Verify the Fix
Test from the CLI first โ no need to reload your app:
php -r "var_dump(preg_match('/your-pattern/', 'test string'));"
A clean result looks like:
int(0) # no match, but no warning
int(1) # match found
If the warning persists, PHP prints it before the int() output. Enable full error reporting to surface everything during debugging:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
Tips
Regex mistakes are easy to introduce and hard to spot in long patterns. Before pushing anything to production, test it interactively. The Regex Tester on ToolCraft lets you drop in a PHP-style pattern, run it against sample strings, and see matches in real time โ nothing leaves your browser. I use it specifically to catch delimiter issues like this before the code ever hits a server.
Three habits that eliminate this warning for good:
- Use
#as your delimiter for any pattern involving URLs or file paths โ no slash escaping needed - Always pass both arguments to
preg_quote($value, $delimiter)โ skipping the second argument won't escape your chosen delimiter - In PHPStorm or VS Code with the PHP Intelephense extension, malformed patterns get underlined before you even run the file

