PostgreSQL Invalid Escape Sequence (SQLSTATE 22025)

PostgreSQL raises ERROR: invalid escape sequence with SQLSTATE 22025 (invalid_escape_sequence) when a string literal or LIKE pattern contains a backslash escape sequence that PostgreSQL does not recognize. You will see a message similar to:

ERROR:  invalid escape sequence: "\m"
LINE 1: SELECT * FROM logs WHERE message LIKE '%\match%';
HINT:  If you meant to write a backslash, use "\\".

The condition name is invalid_escape_sequence and it belongs to error class 22 (Data Exception).

What This Error Means

Error class 22 covers data value problems — situations where the data itself, rather than the SQL syntax, is wrong. SQLSTATE 22025 specifically means PostgreSQL encountered a \ in a string or LIKE/SIMILAR TO pattern and the character that follows it does not form a valid escape sequence.

PostgreSQL recognizes a specific set of C-style escape sequences in escape string literals (strings prefixed with E): \n, \t, \r, \\, \b, \f, \v, \uXXXX, \UXXXXXXXX, \ooo (octal), and \xHH (hex). If the character after \ is not one of these, the engine cannot interpret the sequence and raises 22025.

The behavior depends heavily on the standard_conforming_strings setting. When standard_conforming_strings = on (the default since PostgreSQL 9.1), backslashes in ordinary string literals ('...') are treated as literal characters, not escape characters — so '\m' is just a two-character string. The error arises only inside escape string literals (E'...') or inside LIKE patterns where the escape character is active. When standard_conforming_strings = off (legacy mode still found in older setups or migrated databases), all string literals behave like escape strings, making this error much more common.

After this error is raised, the current transaction is aborted. Any subsequent statements in the same transaction block will fail with ERROR: current transaction is aborted, commands ignored until end of transaction block until you issue ROLLBACK.

Common Causes

  1. Unintended backslash in an E-string literal. Using E'...' syntax and including a \ followed by a character that is not a recognized escape, such as E'\d', E'\m', or E'\p'.

  2. Backslash in a LIKE pattern with standard_conforming_strings = off. In legacy escape mode, '%file\name%' tries to interpret \n as a newline — if the character after \ is unrecognized, PostgreSQL raises 22025 instead of silently ignoring it.

  3. Application code building SQL strings with regex patterns or file paths. Languages like Python, Java, or Ruby often use \d, \w, etc. in regular expressions or \Users\... in Windows paths. When these strings are injected directly into SQL without escaping, the backslashes land inside a PostgreSQL string literal and trigger the error.

  4. Using SIMILAR TO with regex-style escape sequences. SIMILAR TO patterns in PostgreSQL use \ as the default escape for the special characters % and _, but sequences like \d are not valid and will raise 22025.

  5. Migration from MySQL. MySQL interprets \n, \t, and many other sequences in all string literals by default. SQL migrated from MySQL may contain these sequences in ordinary string literals, which then fail under PostgreSQL's escape string rules.

How to Fix invalid_escape_sequence

  1. Double the backslash to produce a literal backslash. Inside an E'...' string, use \\ wherever you want a single \:

    -- Wrong (in legacy mode or E-strings):
    SELECT * FROM files WHERE path LIKE 'C:\Users\%';
    
    -- Correct:
    SELECT * FROM files WHERE path LIKE E'C:\\Users\\%';
    
  2. Switch to dollar-quoting for strings containing many backslashes. Dollar-quoted strings ($$...$$) never interpret backslashes, making them ideal for file paths or regex patterns:

    SELECT * FROM files WHERE path LIKE $$C:\Users\%$$;
    
  3. Avoid E'...' when you do not need escape sequences. Use ordinary single-quoted strings ('...') with standard_conforming_strings = on (the default). In this mode, 'C:\Users\' is a literal string with no escape processing, so backslashes are safe:

    -- Safe with standard_conforming_strings = on (default):
    SELECT * FROM files WHERE path LIKE 'C:\Users\%';
    
  4. Use parameterized queries in application code. The safest fix is to pass strings as bind parameters rather than interpolating them into SQL. The driver handles escaping automatically:

    # Python with psycopg2 — backslashes in the value are passed safely
    cursor.execute(
        "SELECT * FROM files WHERE path LIKE %s",
        (r'C:\Users\%',)
    )
    
  5. Check and set standard_conforming_strings explicitly. If you are migrating from a legacy codebase, verify the setting and update strings accordingly:

    SHOW standard_conforming_strings;
    -- If 'off', consider migrating strings and enabling it:
    SET standard_conforming_strings = on;
    
  6. For LIKE patterns, specify a different escape character or disable escaping. PostgreSQL's LIKE clause supports a custom ESCAPE clause. Setting it to an empty string disables escape processing entirely if backslash handling is causing problems:

    SELECT * FROM logs WHERE message LIKE '%\d+%' ESCAPE '';
    

Additional Information

  • standard_conforming_strings defaulted to off before PostgreSQL 9.1 and to on from 9.1 onward. If you are on a very old cluster or have standard_conforming_strings = off in postgresql.conf, backslash escaping applies to all string literals, making this error significantly more common.
  • Related SQLSTATE codes in class 22: 22019 (invalid_escape_character) — raised when the character specified in a LIKE ... ESCAPE '...' clause is not exactly one character; 22021 (character_not_in_repertoire) — a character encoding issue; 2200C (invalid_use_of_escape_character) — raised in specific contexts where the escape character appears in an invalid position.
  • Client libraries such as libpq, psycopg2, node-postgres, and JDBC all surface this as a PSQLException or similar with the SQLSTATE 22025. Some ORMs (e.g., SQLAlchemy) may wrap it in their own exception hierarchy, but the underlying SQLSTATE is preserved.
  • The escape_string_warning GUC parameter (default on) causes PostgreSQL to emit a WARNING when a backslash appears in a non-escape string literal under standard_conforming_strings = on. This warning is a useful early indicator that code is relying on legacy escape behavior before it breaks in stricter modes.

Frequently Asked Questions

Why does this error only happen in some environments but not others? The most common reason is a difference in standard_conforming_strings between environments. A development database created recently will have standard_conforming_strings = on (safe), while an older production database or one restored from a legacy dump may have it off, causing backslashes to be interpreted as escapes everywhere.

I see this error in a LIKE pattern — how is \ an escape in LIKE? PostgreSQL's LIKE operator uses \ as a default escape character regardless of the standard_conforming_strings setting. This lets you match literal % and _ characters (e.g., '100\%' matches the string 100%). If your pattern contains \ followed by any other character, PostgreSQL raises 22025 because that sequence is not valid for LIKE escaping. Use ESCAPE '' or ESCAPE '!' to change or disable the escape character.

My ORM is generating invalid queries with backslashes — how do I fix it? Use parameterized/prepared statements rather than string interpolation to build queries. For raw SQL methods in ORMs (e.g., Django's RawSQL, SQLAlchemy's text()), pass values as bound parameters. If you must include a literal backslash in a SQL string constant, use $$...$$ dollar-quoting or double the backslash (\\).

Can I suppress this error and treat unrecognized escape sequences as literal characters? No — 22025 is a hard error, not a warning, and cannot be suppressed in the query itself. The correct fix is to write valid escape sequences or avoid escape processing. If you want backslashes to always be literal, use ordinary string literals with standard_conforming_strings = on, which is already the default.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.