Incident brief
Invalid LIKE ESCAPE string
The ESCAPE clause of LIKE accepts an empty string or exactly one character; a multi-character escape string raises this data exception.
In 10 seconds
- What
- Invalid LIKE ESCAPE string
- What triggers it
- Write a LIKE ... ESCAPE '<str>' where the escape string is longer than one character.
- The fix
- Use a single-character escape string, or an empty string to disable escaping.
- Proof
- Reproduced on PostgreSQL 18.4 → A single SELECT reproduces SQLSTATE 22025; the over-long escape string is rejected with a hint about the allowed length.
The fix
What to do right now
The immediate, application-level response to this error.
- Use a single-character escape string, or an empty string to disable escaping.
- If the escape value is dynamic, validate its length before building the LIKE expression.
-- ESCAPE takes one character, or '' to disable escaping.
SELECT 'x' LIKE 'x' ESCAPE '';Diagnose
See it live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Standard triage — not specific to this error
These are canonical PostgreSQL system-catalog queries, shown as SQL to run. No sample output is attached because this is general triage, not a captured lab transcript.This SQLSTATE does not have an error-specific live snapshot yet. These are the canonical system-catalog queries you run against the affected server to see the problem in real time — standard triage, not a reproduced transcript.
What is running right now
Active backends, how long each has been running, and what it is waiting on.
SELECT pid,
state,
wait_event_type,
wait_event,
now() - query_start AS running_for,
left(query, 80) AS query
FROM pg_stat_activity
WHERE state <> 'idle'
AND pid <> pg_backend_pid()
ORDER BY running_for DESC NULLS LAST;Who is blocking whom
Turn raw blocking PIDs into the actual queries on both sides of the wait.
SELECT blocked.pid AS blocked_pid,
blocked.query AS blocked_query,
blocking.pid AS blocking_pid,
blocking.query AS blocking_query
FROM pg_stat_activity AS blocked
JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS b(pid) ON true
JOIN pg_stat_activity AS blocking ON blocking.pid = b.pid
WHERE cardinality(pg_blocking_pids(blocked.pid)) > 0;Locks that are still waiting
Every lock a backend has requested but not yet been granted.
SELECT l.pid,
l.locktype,
l.mode,
l.granted,
COALESCE(c.relname, l.transactionid::text) AS object
FROM pg_locks l
LEFT JOIN pg_class c ON c.oid = l.relation
WHERE NOT l.granted
ORDER BY l.pid;Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual — not paraphrased.
PostgreSQL 18 Documentation — Appendix A. PostgreSQL Error Codes (Table A.1, Class 22 — Data Exception)
22025 → invalid_escape_sequenceRead the full section on postgresql.org →
Passing a multi-character ESCAPE string
LIKE's escape string must be empty or a single character, so a longer string raises 'invalid escape string' with a hint to use one character.The session continues normally
The failing statement ran outside a transaction block, so nothing was left in a bad state — the next statement in the same connection runs normally.Reproduce & verify
A real, single-session PostgreSQL reproduction
A literal transcript of SQL run against a live PostgreSQL instance in an isolated lab — the commands below are exactly what was executed.
- 1Write a LIKE ... ESCAPE '<str>' where the escape string is longer than one character.
- 2PostgreSQL validates the escape string before matching.
- 3Because it is neither empty nor a single character, the statement aborts with SQLSTATE 22025.
A search feature passed a user-supplied escape string straight into LIKE ... ESCAPE, and a multi-character value aborted the query.
-- The error is self-contained in one statement; no schema is required.
SELECT 'no schema needed' AS setup_note;SELECT 'x' LIKE 'x' ESCAPE 'ab';SELECT 'ok' AS session_after_error;What PostgreSQL actually returned
setup_note
------------------
no schema needed
(1 row)ERROR: invalid escape string
HINT: Escape string must be empty or one character. session_after_error
---------------------
ok
(1 row)The same pattern matches once the escape string is empty or one character.
We rerun the match with an empty escape string (escaping disabled) to show it succeeds.
Without this
Before: a multi-character ESCAPE aborts
With this, tested
After: ESCAPE '' matches
What Pro unlocks here
- The exact prevention SQL — copy-paste ready
- Raw psql output captured from the Docker lab
- A senior-DBA action list to take it further
- Live monitoring queries to catch it in production
- The deeper audit: fix-that-fails counterexample, GUC before/after, server-log evidence
Related & next steps
Follow the thread
Everything this error touches — jump straight to the sibling error, term, runbook, or parameter.
Verification
- Last verified
- 2026-07-24 (isolated lab, PostgreSQL 18.4)
- Reviewed by
- Verified against PostgreSQL 18.4 in an isolated lab environment
- Audit status
- reviewed