2026년 06월 08일 | DBMS Error 가이드
이 글에서 다루는 내용
2200D 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2200D invalid escape octet 란?
PostgreSQL 에러 코드 2200D: invalid escape octet는 바이너리 데이터(bytea 타입)를 다룰 때 이스케이프 시퀀스가 잘못된 형식으로 입력되었을 때 발생하는 에러입니다. PostgreSQL의 bytea 타입은 이진 데이터를 저장하기 위해 특수한 이스케이프 표기법을 사용하는데, 이 규칙을 올바르게 따르지 않으면 해당 에러가 발생합니다. 특히 레거시 애플리케이션에서 escape 형식의 bytea 리터럴을 직접 조합하거나, 외부 시스템에서 데이터를 마이그레이션할 때 자주 접할 수 있는 에러입니다.
주요 발생 원인
1. bytea escape 형식에서 잘못된 octet 값 사용
PostgreSQL의 전통적인 escape 포맷에서 bytea 리터럴은 \nnn 형식(8진수 3자리)으로 표현됩니다. 예를 들어 \377은 유효하지만, \400처럼 8진수 범위(0~377)를 초과하거나 \9처럼 8진수가 아닌 숫자를 사용하면 invalid escape octet 에러가 발생합니다. 이 문제는 주로 애플리케이션 코드에서 바이트 값을 문자열로 직접 조합할 때 발생하며, 개발자가 8진수와 10진수를 혼동하는 경우가 많습니다.
2. bytea_output 설정과 입력 포맷의 불일치
PostgreSQL 9.0부터는 bytea의 기본 출력 포맷이 hex로 변경되었지만, 일부 레거시 시스템은 여전히 escape 포맷으로 데이터를 주고받습니다. 애플리케이션이 hex 포맷으로 출력된 bytea 값을 그대로 다시 escape 포맷으로 처리하려 할 때, 또는 반대의 경우에 이스케이프 규칙이 맞지 않아 에러가 발생할 수 있습니다. 특히 ORM이나 드라이버 버전이 서버 버전과 맞지 않을 때 자주 목격되는 패턴입니다.
3. 외부 데이터 마이그레이션 및 수동 SQL 작성 오류
다른 데이터베이스(Oracle, MySQL 등)에서 PostgreSQL로 데이터를 마이그레이션하는 과정에서 바이너리 데이터를 변환할 때, 각 데이터베이스의 이진 데이터 표기법 차이를 고려하지 않으면 잘못된 이스케이프 시퀀스가 삽입될 수 있습니다. 또한 DBA나 개발자가 수동으로 INSERT 쿼리를 작성할 때 \ 문자 처리를 잘못하여 에러가 발생하는 경우도 많습니다. 이 경우는 E'' 이스케이프 문자열 리터럴 사용 여부와 PostgreSQL의 standard_conforming_strings 설정이 결과에 크게 영향을 미칩니다.
해결 방법
원인 1 해결: 올바른 8진수 이스케이프 사용
bytea escape 포맷에서는 반드시 0~377 범위의 3자리 8진수를 사용해야 합니다.
-- 잘못된 예 (에러 발생)
-- \400은 8진수 범위 초과
SELECT E'\\400'::bytea;
-- ERROR: invalid escape octet
-- 올바른 예 (0~377 범위의 유효한 8진수)
SELECT E'\\377'::bytea; -- 10진수로 255
SELECT E'\\101'::bytea; -- 'A' 문자 (10진수 65)
SELECT E'\\000'::bytea; -- null byte
-- bytea 값 확인
SELECT E'\\101\\102\\103'::bytea;
-- 결과: \x414243 (hex 포맷) 또는 ABC (escape 포맷)
원인 2 해결: hex 포맷으로 전환 및 설정 확인
PostgreSQL 9.0 이상에서는 hex 포맷 사용을 강력히 권장합니다.
-- 현재 bytea_output 설정 확인
SHOW bytea_output;
-- hex 포맷으로 명시적 변환 (권장 방식)
-- \x 접두사를 사용한 hex 리터럴
SELECT '\xDEADBEEF'::bytea;
SELECT '\x48656C6C6F'::bytea; -- 'Hello'
-- 세션 레벨에서 bytea_output 설정 변경
SET bytea_output = 'escape';
SELECT '\x48656C6C6F'::bytea; -- escape 포맷으로 출력
SET bytea_output = 'hex';
SELECT '\x48656C6C6F'::bytea; -- hex 포맷으로 출력
-- 애플리케이션 레벨에서 bytea를 hex 문자열로 변환
SELECT encode('\xDEADBEEF'::bytea, 'hex'); -- 'deadbeef'
SELECT encode('\xDEADBEEF'::bytea, 'base64'); -- base64 인코딩
SELECT decode('deadbeef', 'hex'); -- hex → bytea
SELECT decode('SGVsbG8=', 'base64'); -- base64 → bytea
원인 3 해결: 마이그레이션 시 안전한 변환 방법
-- 다른 DB에서 마이그레이션 시 decode 함수를 활용한 안전한 삽입
CREATE TABLE binary_data (
id SERIAL PRIMARY KEY,
data bytea,
description TEXT
);
-- 방법 1: hex 문자열을 bytea로 변환하여 삽입 (가장 안전)
INSERT INTO binary_data (data, description)
VALUES (decode('89504e470d0a1a0a', 'hex'), 'PNG header bytes');
-- 방법 2: base64 인코딩된 데이터 삽입
INSERT INTO binary_data (data, description)
VALUES (decode('iVBORw0KGgo=', 'base64'), 'PNG data base64');
-- 방법 3: 문자열을 bytea로 캐스팅 (일반 텍스트)
INSERT INTO binary_data (data, description)
VALUES (convert_to('Hello, World!', 'UTF8'), 'Text as bytea');
-- bytea 데이터 읽기 및 변환
SELECT
id,
encode(data, 'hex') AS hex_representation,
encode(data, 'base64') AS base64_representation,
octet_length(data) AS byte_length
FROM binary_data;
-- 잘못된 escape 시퀀스를 포함한 기존 데이터 정제
-- (마이그레이션 후 데이터 검증)
DO $$
DECLARE
v_row RECORD;
BEGIN
FOR v_row IN SELECT id, data FROM binary_data LOOP
BEGIN
-- 데이터 유효성 확인
PERFORM octet_length(v_row.data);
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'Invalid bytea at id=%: %', v_row.id, SQLERRM;
END;
END LOOP;
END;
$$;
standard_conforming_strings 설정 관련 해결
-- 현재 설정 확인
SHOW standard_conforming_strings;
-- standard_conforming_strings = on (기본값, PostgreSQL 9.1+)일 때
-- 백슬래시를 이스케이프하려면 E'' 접두사 사용 필요
SELECT E'\\001\\002\\003'::bytea; -- E'' prefix with double backslash
-- standard_conforming_strings = off일 때
-- 단일 백슬래시도 이스케이프로 처리됨 (레거시 동작)
-- 가급적 on 상태를 유지하고 E'' 접두사를 명시적으로 사용 권장
-- 올바른 bytea 리터럴 작성 패턴
-- (standard_conforming_strings 설정과 무관하게 동작)
SELECT E'\\x41'::bytea; -- 'A' (escape 포맷, 8진수 0x41 = 65)
SELECT '\x41'::bytea; -- hex 포맷, 0x41 = 'A'
예방 방법
1. hex 포맷을 표준으로 사용하고 encode/decode 함수 적극 활용
신규 개발 및 마이그레이션 프로젝트에서는 항상 \x 접두사를 사용하는 hex 포맷을 표준으로 지정하세요. Escape 포맷은 가독성이 낮고 실수가 발생하기 쉬우므로, 팀 내 코딩 컨벤션에 hex 포맷 사용을 명문화하는 것이 좋습니다. 또한 바이너리 데이터를 삽입하거나 조회할 때는 반드시 encode(), decode() 함수를 사용하여 안전하게 처리하세요.
-- 팀 표준 설정 (postgresql.conf 또는 ALTER DATABASE)
ALTER DATABASE mydb SET bytea_output = 'hex';
-- 애플리케이션 연결 시 항상 명시적 설정
-- psql 접속 후
SET bytea_output = 'hex';
-- 안전한 bytea 처리 함수 래퍼 예시
CREATE OR REPLACE FUNCTION safe_bytea_from_hex(p_hex TEXT)
RETURNS bytea
LANGUAGE plpgsql
AS $$
BEGIN
RETURN decode(p_hex, 'hex');
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Invalid hex string: %', p_hex;
END;
$$;
2. 입력 데이터 유효성 검사 및 마이그레이션 전 사전 검증
바이너리 데이터를 외부에서 받거나 마이그레이션할 때는 반드시 사전에 데이터 포맷을 검증하는 절차를 마련하세요. 특히 레거시 시스템으로부터 데이터를 가져올 때는 staging 테이블에 TEXT 타입으로 먼저 적재한 후, 변환 로직을 검증한 뒤 최종 bytea 컬럼으로 이동하는 2단계 접근 방식이 안전합니다.
-- 2단계 마이그레이션 패턴 예시
-- Step 1: staging 테이블에 text로 적재
CREATE TABLE staging_binary (
id INT,
raw_data TEXT -- 일단 TEXT로 받음
);
-- Step 2: 유효성 검사 후 본 테이블로 이동
INSERT INTO binary_data (id, data)
SELECT
id,
CASE
WHEN raw_data ~ '^[0-9a-fA-F]+$' THEN decode(raw_data, 'hex')
ELSE NULL
END AS data
FROM staging_binary
WHERE raw_data IS NOT NULL;
-- 변환 실패 데이터 확인
SELECT id, raw_data
FROM staging_binary
WHERE raw_data !~ '^[0-9a-fA-F]+$';
관련 에러
- 22P03
invalid_binary_representation: bytea 또는 다른 바이너리 타입의 입력 자체가 해당 타입의 이진 표현 규칙을 위반했을 때 발생합니다.2200D가 이스케이프 시퀀스의 문법적 오류라면, 이 에러는 데이터 자체의 구조적 불일치를 의미합니다. - 22021
character_not_in_repertoire: 문자 인코딩 변환 과정에서 대상 인코딩에 존재하지 않는 문자가 포함되었을 때 발생합니다. bytea와 TEXT 간 변환 시 함께 마주칠 수 있습니다. - 22000
data_exception: 데이터 관련 예외의 상위 카테고리 에러로,2200D를 포함한 다양한 데이터 형식 오류의 부모 클래스입니다. PL/pgSQL에서WHEN data_exception으로 광범위하게 처리할 수 있습니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.