Python SyntaxWarning: Invalid Escape Sequence (tested)
SyntaxWarning: invalid escape sequence fires when a string literal contains a backslash followed by a letter Python doesn't recognize as a string escape — most often a regex pattern like "\d+" written without the r prefix. We reproduced it, turned it into a real crash, and tested the fix.
1. Reproduced: the plain case
$ cat bad.py
import re
pattern = re.compile("\d+")
m = pattern.match("123")
print(m)
$ python3 bad.py
<re.Match object; span=(0, 3), match='123'>
bad.py:2: SyntaxWarning: invalid escape sequence '\d'
pattern = re.compile("\d+")
The script still runs and still matches — exit code 0. That's what makes this warning easy to ignore: \d inside a plain string isn't a valid Python escape, so Python keeps the backslash and the letter literally, which happens to be exactly what the regex engine wants. It works today by coincidence, not by design, and Python tells you so.
2. Reproduced: strict mode turns it into a crash
Run the identical file with warnings promoted to errors:
$ python3 -W error bad.py
File "bad.py", line 2
pattern = re.compile("\d+")
^^
SyntaxError: invalid escape sequence '\d'
$ echo $?
1
Same file, same line, but now it's a SyntaxError raised before a single line of the script runs, because the warning fires at compile time, not when re.compile() executes. Some test runners and CI configs enable -W error (or PYTHONWARNINGS=error) by default, so code that "works" interactively can fail in CI the moment this flag is on.
3. Why some escapes warn and others don't
Python string literals recognize a fixed set of backslash escapes: \n, \t, \\, \', \x41, and a few more. We confirmed a recognized one produces no warning at all:
$ python3 -W error -c "import re; re.compile('line1\nline2')"
(no output, exit 0)
\d, \s, \w, \b and similar regex tokens are not in that list. They only mean something to the regex engine, after the string literal has already been parsed. Python has to guess what you meant, and it guesses "probably a typo," which is why it warns.
4. Reproduced: the fix — a raw string
$ cat fixed.py
import re
pattern = re.compile(r"\d+")
m = pattern.match("123")
print(m)
$ python3 -W error fixed.py
<re.Match object; span=(0, 3), match='123'>
$ echo $?
0
The r prefix tells Python not to process backslash escapes at all, so the string is passed to the regex engine exactly as typed, with no warning even under -W error. This is the fix for every case we tested. Prefix every regex pattern string with r, not just the ones that currently warn — it costs nothing and removes the ambiguity for good.
5. The other fix: double the backslash
Doubling the backslash also silences the warning, because \\ is itself a recognized escape (a literal backslash):
$ cat double_backslash.py
import re
p = re.compile("\\d+")
print(p.match("42"))
$ python3 -W error double_backslash.py
<re.Match object; span=(0, 2), match='42'>
This works but reads worse than a raw string once a pattern has more than one or two backslashes — we'd use r"..." everywhere and reserve double-backslashing for the rare case where you deliberately need the string engine to process other escapes alongside the regex.
6. A gotcha we measured: filtering the warning doesn't always catch it
Because the warning fires when the string literal is compiled, setting a filter at runtime in the same file is too late for code above it, but it does apply to a module compiled afterward, such as one imported later in the same process:
$ cat warn2.py
import warnings
warnings.filterwarnings('error', category=SyntaxWarning)
import re2mod # re2mod.py: re.compile("\s\w")
$ python3 warn2.py
Traceback (most recent call last):
File "warn2.py", line 3, in <module>
import re2mod
File "re2mod.py", line 2
re.compile("\s\w")
^^
SyntaxError: invalid escape sequence '\s'
If you're trying to catch these warnings deliberately (for example in a test), set the filter before anything with a bad pattern is imported, or run with -W error from the start — don't rely on a filter set mid-script to catch literals compiled earlier in that same file.
7. Checklist
- Any regex pattern written as a plain string: change it to
r"...". f"\d{{n}}"f-strings need the prefix too:rf"\d{{n}}".- If CI fails on this but your machine doesn't, check for
PYTHONWARNINGS=erroror-W errorin the CI config — that's what's promoting the warning to a crash. - Don't just double the backslash across a whole codebase to silence it — a raw string is clearer and we found no case where it didn't work.
Once your pattern compiles cleanly, make sure it also runs fast on adversarial input — see regex catastrophic backtracking for a different regex failure mode we measured on the same box.
Frequently asked questions
Why does \d warn but \n doesn't?
\n is on Python's fixed list of recognized string escapes, so it's processed before the regex engine ever sees the string. \d isn't on that list — it only means something to the regex engine — so Python warns that it doesn't recognize the escape and is keeping it literally, which happens to be what the regex engine wants.
Does python3 -W error always turn this into a crash?
On this box, yes: we reproduced the identical file going from a silent warning under plain python3 to a SyntaxError and exit code 1 under python3 -W error, with no other change. Any environment that sets PYTHONWARNINGS=error behaves the same way.
Does prefixing with r always fix it?
In every case we tested, yes — r"\d+" compiled and matched with zero warnings, even under -W error. The raw-string prefix stops Python from interpreting backslash escapes in that literal at all, so there's nothing left for the warning to flag.
Will this become a hard error in a future Python version, not just a warning?
Per the Python changelog (not something we measured), invalid escape sequences were a DeprecationWarning in older 3.x versions and became SyntaxWarning in 3.12; the documented intent is to eventually make them a syntax error by default. Fix it now rather than waiting.
Is my regex wrong if I see this warning?
Not necessarily — we measured the exact same match result (span, matched text) with and without the warning, because \d was already being passed through to the regex engine either way. The warning is about the string literal being ambiguous, not about the regex being incorrect.
Written with AI assistance. Measured on 2026-10-03 with CPython 3.13.5 on a real Linux box. Every warning, traceback and exit code below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python is free.