PostgreSQL 22P03 오류 원인과 해결 방법 완벽 가이드

22P03
2026년 08월 18일 | DBMS Error 가이드

이 글에서 다루는 내용

22P03 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.

22P03 invalid binary representation 는?

PostgreSQL 에러 코드 22P03 invalid binary representation은 데이터를 바이너리 형식으로 변환하거나 수신하는 과정에서 해당 데이터가 대상 데이터 타입의 유효한 바이너리 표현 형식을 따르지 않을 때 발생합니다. 주로 COPY 명령어를 통해 바이너리 포맷 데이터를 적재하거나, 클라이언트 드라이버가 바이너리 프로토콜로 데이터를 전송할 때, 또는 형변환(CAST) 과정에서 잘못된 바이너리 데이터가 입력될 때 나타납니다. 텍스트 포맷과 달리 바이너리 포맷은 PostgreSQL 내부 규격을 엄격히 따라야 하므로, 버전 간 호환성 문제나 외부 시스템과의 연동 시 자주 발생하는 에러입니다.


주요 발생 원인

1. COPY 명령어에서 잘못된 바이너리 포맷 사용

COPY ... WITH (FORMAT BINARY) 구문을 사용할 때 입력 파일이 PostgreSQL의 바이너리 포맷 규격을 따르지 않는 경우가 가장 흔한 원인입니다. PostgreSQL 바이너리 COPY 포맷은 특정 시그니처 헤더(PGCOPY\n\377\r\n\0)와 필드 길이 정보를 포함해야 하는데, 일반 텍스트 파일이나 다른 DB에서 내보낸 바이너리 파일을 그대로 사용하면 이 에러가 발생합니다. 특히 다른 PostgreSQL 버전에서 덤프한 바이너리 파일을 상위/하위 버전에 적재할 때도 호환성 문제로 발생할 수 있습니다.

2. 클라이언트 드라이버의 바이너리 프로토콜 불일치

JDBC, psycopg2, libpq 등 클라이언트 드라이버가 바이너리 프로토콜을 통해 파라미터를 전송할 때 데이터 타입의 바이너리 인코딩이 PostgreSQL 서버의 기대값과 맞지 않는 경우 발생합니다. 예를 들어, Java의 JDBC 드라이버에서 PreparedStatement를 사용하여 uuid, inet, jsonb 등의 데이터 타입에 잘못 인코딩된 바이트 배열을 전달하거나, 드라이버 버전과 PostgreSQL 서버 버전 간의 바이너리 포맷 차이가 있을 때 이 에러가 트리거됩니다. 이 경우 드라이버 측에서 텍스트 프로토콜을 강제 사용하는 옵션으로 우회할 수 있습니다.

3. 잘못된 형변환(CAST) 또는 사용자 정의 타입 처리

사용자 정의 데이터 타입(DOMAIN, COMPOSITE TYPE, ENUM 등)이나 특수 타입(bytea, uuid, hstore)에 대해 잘못된 바이너리 값으로 형변환을 시도할 때 발생합니다. 특히 bytea 타입은 hex 또는 escape 인코딩 방식을 따라야 하는데, 원시 바이너리 바이트를 직접 삽입하려 할 때 이 에러가 발생합니다. 또한 복잡한 복합 타입(COMPOSITE TYPE)의 경우 내부 필드 순서나 타입이 맞지 않는 바이너리 데이터를 역직렬화하려 할 때도 동일한 에러가 발생합니다.


해결 방법

원인 1 해결: COPY 바이너리 포맷 문제 수정

바이너리 COPY 대신 텍스트 또는 CSV 포맷을 사용하거나, 반드시 바이너리를 써야 한다면 같은 버전의 PostgreSQL에서 덤프한 파일을 사용하세요.

-- 잘못된 방법: 일반 텍스트 파일을 바이너리로 COPY 시도
COPY employees FROM '/tmp/employees.bin' WITH (FORMAT BINARY);
-- ERROR: 22P03 invalid binary representation

-- 올바른 방법 1: TEXT 포맷 사용
COPY employees FROM '/tmp/employees.txt' WITH (FORMAT TEXT, DELIMITER ',');

-- 올바른 방법 2: CSV 포맷 사용
COPY employees FROM '/tmp/employees.csv' WITH (FORMAT CSV, HEADER true);

-- 올바른 방법 3: 같은 PostgreSQL 버전에서 바이너리 덤프 후 적재
-- 덤프 시
COPY employees TO '/tmp/employees_bin.dump' WITH (FORMAT BINARY);
-- 적재 시 (동일 버전에서만 보장)
COPY employees FROM '/tmp/employees_bin.dump' WITH (FORMAT BINARY);

-- 바이너리 COPY 파일의 유효성 확인 (헤더 체크)
-- psql 에서 확인: 첫 11바이트가 'PGCOPY\n\377\r\n\0' 이어야 함
-- 아래 쿼리로 bytea로 읽어서 확인
SELECT substring(pg_read_binary_file('/tmp/employees_bin.dump')::bytea FROM 1 FOR 11);

원인 2 해결: 클라이언트 드라이버 바이너리 프로토콜 문제

드라이버 설정에서 바이너리 프로토콜을 비활성화하거나 텍스트 모드를 강제 사용합니다.

-- PostgreSQL 서버 측에서 세션 레벨로 디버깅
-- 클라이언트가 보내는 바이너리 값을 텍스트로 우회 받기

-- 예시: uuid 타입 삽입 시 텍스트 형변환 명시
CREATE TABLE test_uuid (
    id uuid PRIMARY KEY,
    name TEXT
);

-- 바이너리 인코딩 문제가 있는 경우, 텍스트로 명시적 캐스팅
INSERT INTO test_uuid (id, name)
VALUES ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, 'test_user');

-- inet 타입도 마찬가지로 명시적 캐스팅 권장
CREATE TABLE server_info (
    server_ip inet,
    description TEXT
);

INSERT INTO server_info (server_ip, description)
VALUES ('192.168.1.100'::inet, 'Web Server');

-- psycopg2에서 바이너리 프로토콜 비활성화 예시 (Python 주석 형태)
-- conn = psycopg2.connect(dsn, binary=False)  -- 이 옵션으로 텍스트 모드 강제

-- JDBC 연결 URL에서 바이너리 모드 비활성화
-- jdbc:postgresql://host/db?preferQueryMode=simple

원인 3 해결: 잘못된 형변환 및 bytea 처리

bytea 타입은 올바른 인코딩 방식을 사용하고, 형변환 시 명시적으로 타입을 지정합니다.

-- bytea 타입 올바른 사용법
-- 잘못된 방법: 원시 문자열 직접 삽입
-- INSERT INTO binary_data (data) VALUES ('raw binary content');

-- 올바른 방법 1: hex 인코딩 사용 (PostgreSQL 기본 권장)
INSERT INTO binary_data (data) VALUES (decode('DEADBEEF', 'hex'));

-- 올바른 방법 2: escape 포맷 사용
INSERT INTO binary_data (data) VALUES (E'\\xDEADBEEF'::bytea);

-- 올바른 방법 3: 파일에서 bytea로 읽기
SELECT pg_read_binary_file('/tmp/image.png')::bytea;

-- bytea_output 설정 확인
SHOW bytea_output;  -- 'hex' 또는 'escape'

-- hex 포맷으로 설정 (권장)
SET bytea_output = 'hex';

-- 복합 타입 (COMPOSITE TYPE) 올바른 사용
CREATE TYPE address_type AS (
    street TEXT,
    city   TEXT,
    zip    VARCHAR(10)
);

CREATE TABLE employees (
    emp_id  SERIAL PRIMARY KEY,
    name    TEXT,
    address address_type
);

-- 올바른 복합 타입 삽입
INSERT INTO employees (name, address)
VALUES ('홍길동', ROW('서울시 강남구 테헤란로', '서울', '06234')::address_type);

-- 잘못된 바이너리 표현인지 확인하는 진단 쿼리
DO $$
DECLARE
    v_result TEXT;
BEGIN
    BEGIN
        SELECT '잘못된값'::uuid INTO v_result;
    EXCEPTION WHEN invalid_binary_representation THEN
        RAISE NOTICE '22P03 에러 감지: %', SQLERRM;
    END;
END;
$$;

예방 방법

1. 데이터 타입 유효성 검증 로직 도입

운영 환경에 데이터를 적재하기 전에 반드시 스테이징 환경에서 바이너리 포맷 유효성을 사전 검증하는 절차를 수립하세요. 아래와 같이 저장 프로시저나 체크 함수를 만들어 두면 22P03 에러를 사전에 차단할 수 있습니다.

-- 안전한 UUID 변환 함수 예시
CREATE OR REPLACE FUNCTION safe_cast_uuid(input_text TEXT)
RETURNS UUID AS $$
BEGIN
    RETURN input_text::uuid;
EXCEPTION WHEN invalid_text_representation OR invalid_binary_representation THEN
    RAISE WARNING '유효하지 않은 UUID 값: %', input_text;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

-- 사용 예시
SELECT safe_cast_uuid('valid-uuid-here');
SELECT safe_cast_uuid('invalid-value');  -- WARNING 출력 후 NULL 반환

-- COPY 전 파일 포맷 검증 (헤더 시그니처 확인)
CREATE OR REPLACE FUNCTION validate_binary_copy_header(file_path TEXT)
RETURNS BOOLEAN AS $$
DECLARE
    header_bytes bytea;
    expected_sig bytea := E'PGCOPY\n\377\r\n\0';
BEGIN
    header_bytes := substring(pg_read_binary_file(file_path)::bytea FROM 1 FOR 11);
    IF header_bytes = expected_sig THEN
        RETURN TRUE;
    ELSE
        RAISE WARNING '유효하지 않은 바이너리 COPY 파일 헤더: %', file_path;
        RETURN FALSE;
    END IF;
END;
$$ LANGUAGE plpgsql;

2. 클라이언트 드라이버 버전 관리 및 텍스트 모드 우선 정책 수립

바이너리 프로토콜은 성능상 이점이 있지만, 드라이버 버전과 PostgreSQL 서버 버전 간의 호환성 문제를 유발할 수 있습니다. 신규 시스템 연동 시에는 텍스트 프로토콜을 기본값으로 설정하고, 충분한 검증 후에만 바이너리 프로토콜로 전환하는 정책을 운영 표준으로 삼으세요. 또한 pg_upgrade, 메이저 버전 업그레이드 후에는 바이너리 COPY 파일 재생성 여부를 반드시 검토하고, 드라이버 버전을 PostgreSQL 서버 버전에 맞게 업데이트하는 것을 릴리즈 체크리스트에 포함시키는 것을 강력히 권장합니다.


관련 에러

  • 22P02 invalid_text_representation: 텍스트 포맷의 잘못된 표현. 바이너리가 아닌 텍스트 형식으로 데이터를 입력할 때 유사한 상황에서 발생합니다.
  • 22000 data_exception: 데이터 관련 일반 예외의 부모 클래스로, 22P03은 이 카테고리에 속합니다.
  • 42804 datatype_mismatch: 형변환 과정에서 타입이 맞지 않을 때 발생하며, 바이너리 표현 문제와 함께 나타날 수 있습니다.
  • 22021 character_not_in_repertoire: 잘못된 문자 인코딩 관련 에러로, 바이너리/텍스트 인코딩 혼용 시 함께 발생하는 경우가 있습니다.

DBMS 에러 코드 시리즈

주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.

본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.

댓글 남기기