Incident brief
Untranslatable character between encodings
Converting text to a target encoding fails when a character has no representation there; the euro sign (U+20AC) has no LATIN1 equivalent.
What lands in your log
ERROR: character with byte sequence 0xe2 0x82 0xac in encoding "UTF8" has no equivalent in encoding "LATIN1"
In 10 seconds
- What triggers it
- Call convert_to(text, encoding) where the text contains a character the target encoding cannot represent.
- Fix
- Convert to an encoding that can represent the characters (UTF8 or LATIN9 cover the euro sign).
- Proof
- Reproduced on PostgreSQL 18.4 → A single SELECT reproduces SQLSTATE 22P05; the euro sign cannot be encoded as LATIN1 and the conversion is refused.
Fix
What to do right now
Application-level steps for this error.
- Convert to an encoding that can represent the characters (UTF8 or LATIN9 cover the euro sign).
- Strip or transliterate unsupported characters before converting to a narrow encoding like LATIN1.
-- Convert only characters the target encoding can represent.
SELECT convert_to('EUR', 'LATIN1');For this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Untranslatable character between encodings is an encoding-boundary failure. Capture the original bytes before any lossy application decode, then confirm client/server encodings.
Client/server encoding and available conversions
Read the encoding contract PostgreSQL is enforcing.
SELECT current_setting('client_encoding') AS client_encoding,
current_setting('server_encoding') AS server_encoding;
SELECT conname, pg_encoding_to_char(conforencoding) AS source_encoding,
pg_encoding_to_char(contoencoding) AS target_encoding
FROM pg_conversion
ORDER BY conname
LIMIT 50;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)
22P05 → untranslatable_characterRead the full section on postgresql.org →
Converting an unrepresentable character
The euro sign exists in UTF-8 but has no code point in LATIN1, so PostgreSQL raises 'has no equivalent in encoding LATIN1'.The session continues normally
The encoding failure happened outside a transaction, so it leaves no dangling state, the next statement in the same session runs fine.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.
- 1Call convert_to(text, encoding) where the text contains a character the target encoding cannot represent.
- 2PostgreSQL walks the string and reaches the euro sign, whose UTF-8 bytes 0xe2 0x82 0xac have no LATIN1 mapping.
- 3The conversion aborts with SQLSTATE 22P05.
An export pipeline forced UTF-8 data into a legacy LATIN1 file and broke on the first row containing a euro sign.
-- The error is self-contained in one statement; no schema is required.
SELECT 'no schema needed' AS setup_note;SELECT convert_to(U&'\20AC', 'LATIN1');SELECT 'ok' AS session_after_error;What PostgreSQL actually returned
setup_note
------------------
no schema needed
(1 row)ERROR: character with byte sequence 0xe2 0x82 0xac in encoding "UTF8" has no equivalent in encoding "LATIN1" session_after_error
---------------------
ok
(1 row)An all-ASCII string converts to the same narrow encoding without error.
Without this
Before: the euro sign has no LATIN1 form
With this, tested
After: 'EUR' converts cleanly
- A second operational test: exact SQL, raw output, measured result, and engineer notes
Card required. Cancel before day 7 and you are not charged.
Connected
Everything this error touches
Every page this SQLSTATE connects to: the concept that explains it, the runbooks that fix it, the parameters you tune to prevent it, and the sibling errors it travels with. All real cross-references. Jump straight in, or open the full interactive map.
Verification
- Last verified
- 2026-07-24 (isolated lab, PostgreSQL 18.4)
- Verification scope
- Verified against PostgreSQL 18.4 in an isolated lab environment
- Audit status
- reviewed
Went further?
Pro unlocks the second lab proof
Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.