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

22P04
2026년 06월 14일 | DBMS Error 가이드

이 글에서 다루는 내용

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

22P04 bad copy file format 는?

PostgreSQL 에러 코드 22P04bad copy file format으로, COPY 명령어를 사용하여 데이터를 가져오거나 내보낼 때 파일의 형식이 예상한 포맷과 일치하지 않을 때 발생합니다. 예를 들어 CSV 형식으로 파일을 읽도록 지정했지만 실제 파일이 탭 구분자(TSV)로 작성되어 있거나, 바이너리 포맷으로 내보낸 파일을 텍스트 모드로 읽으려 할 때 이 에러가 발생합니다. 이 에러는 대용량 데이터 마이그레이션, ETL 파이프라인, 또는 외부 시스템과의 데이터 연동 작업 중에 자주 발생하며, 데이터 로딩 작업 전체를 중단시키므로 빠르게 원인을 파악하고 대처하는 것이 중요합니다.


주요 발생 원인

  • 잘못된 파일 포맷 지정 (CSV vs TEXT vs BINARY 불일치)

가장 흔한 원인입니다. PostgreSQL의 COPY 명령은 TEXT, CSV, BINARY 세 가지 포맷을 지원하는데, 실제 파일의 포맷과 명령어에 지정한 포맷이 다를 경우 에러가 발생합니다. 예를 들어 바이너리 형식(pg_dump 등으로 덤프된 파일)으로 저장된 파일을 CSV 옵션으로 읽으려 하거나, 탭으로 구분된 텍스트 파일을 구분자 설정 없이 CSV로 읽으려 할 때 이 에러가 발생합니다. 실무에서는 파일을 직접 열어 첫 몇 줄을 확인하거나 file 명령어로 파일 형식을 먼저 검증하는 것이 좋습니다.

  • 잘못된 구분자(Delimiter) 또는 인용 부호(Quote) 설정

CSV 파일이라도 구분자가 쉼표(,)가 아닌 세미콜론(;), 파이프(|), 탭(\t) 등으로 되어 있을 수 있습니다. 이 경우 PostgreSQL은 각 행을 올바르게 파싱하지 못하고, 컬럼 수 불일치 또는 포맷 에러를 발생시킵니다. 또한 인용 부호 문자가 큰따옴표(")가 아닌 다른 문자로 지정되어 있거나, 이스케이프 문자 설정이 맞지 않을 때도 동일한 에러가 발생할 수 있습니다.

  • 파일 인코딩 불일치 또는 BOM(Byte Order Mark) 존재

파일이 UTF-8이 아닌 EUC-KR, CP949, Latin-1 등의 인코딩으로 저장되어 있거나, Windows에서 생성된 CSV 파일에 UTF-8 BOM(\xEF\xBB\xBF)이 포함되어 있을 경우 PostgreSQL이 첫 번째 줄을 올바르게 파싱하지 못합니다. 특히 한국 환경에서는 Excel로 저장한 CSV 파일이 EUC-KR 또는 CP949로 인코딩되는 경우가 많아 이 문제가 자주 발생합니다. BOM이 포함된 파일은 첫 번째 컬럼명이나 데이터가 깨져 보이므로 반드시 사전 확인이 필요합니다.


해결 방법

원인 1: 포맷 불일치 해결

파일의 실제 포맷을 확인한 후, 맞는 옵션을 사용합니다.

-- 잘못된 예: 바이너리 파일을 CSV로 읽으려 할 때
COPY employees FROM '/data/employees.bin' WITH (FORMAT CSV);

-- 올바른 예: 바이너리 포맷 명시
COPY employees FROM '/data/employees.bin' WITH (FORMAT BINARY);

-- 텍스트 포맷 (기본 탭 구분자)
COPY employees FROM '/data/employees.txt' WITH (FORMAT TEXT);

-- CSV 포맷 명시
COPY employees FROM '/data/employees.csv' WITH (FORMAT CSV, HEADER true);

원인 2: 구분자 및 인용 부호 설정 수정

-- 세미콜론(;) 구분자 파일 처리
COPY employees FROM '/data/employees.csv'
WITH (
    FORMAT CSV,
    DELIMITER ';',
    HEADER true
);

-- 파이프(|) 구분자 파일 처리
COPY employees FROM '/data/employees.csv'
WITH (
    FORMAT CSV,
    DELIMITER '|',
    HEADER true
);

-- 탭 구분자 파일 처리 (TSV)
COPY employees FROM '/data/employees.tsv'
WITH (
    FORMAT TEXT,
    DELIMITER E'\t'
);

-- 인용 부호 및 이스케이프 문자 커스텀 설정
COPY employees FROM '/data/employees.csv'
WITH (
    FORMAT CSV,
    DELIMITER ',',
    QUOTE '''',       -- 작은따옴표를 인용 부호로 사용
    ESCAPE '\',
    HEADER true
);

원인 3: 인코딩 불일치 및 BOM 처리

-- EUC-KR 인코딩 파일 로딩
COPY employees FROM '/data/employees_euckr.csv'
WITH (
    FORMAT CSV,
    HEADER true,
    ENCODING 'EUC_KR'
);

-- UTF-8 BOM이 포함된 파일은 사전에 BOM 제거 후 로딩
-- Linux 터미널에서 BOM 제거:
-- sed -i '1s/^\xEF\xBB\xBF//' employees.csv

-- 또는 psql에서 \copy 사용 시 파이프로 BOM 제거 후 전달
-- psql 명령어 예:
-- psql -c "\copy employees FROM PROGRAM 'sed ''1s/^\xEF\xBB\xBF//'' /data/employees.csv' WITH (FORMAT CSV, HEADER true)"

디버깅을 위한 소량 데이터 테스트

-- 먼저 소량의 데이터로 포맷 확인
-- 임시 테이블 생성
CREATE TEMP TABLE employees_test (LIKE employees);

-- COPY 에러 발생 시 에러 행 확인을 위해 COPY 대신 file_fdw 활용
CREATE EXTENSION IF NOT EXISTS file_fdw;
CREATE SERVER import_server FOREIGN DATA WRAPPER file_fdw;

-- 외부 테이블로 파일 내용 확인 (포맷 검증)
CREATE FOREIGN TABLE employees_fdw (
    id INT,
    name TEXT,
    department TEXT
)
SERVER import_server
OPTIONS (
    filename '/data/employees.csv',
    format 'csv',
    header 'true',
    delimiter ','
);

SELECT * FROM employees_fdw LIMIT 10;

예방 방법

  • 데이터 로딩 전 파일 검증 자동화

운영 환경에서는 COPY 명령 실행 전 파일의 인코딩, 구분자, 헤더 유무를 자동으로 검증하는 사전 점검 스크립트를 도입하세요. Python의 chardet 라이브러리나 Linux의 file, iconv 명령어를 활용해 파일 메타정보를 확인하고, 이를 CI/CD 파이프라인이나 ETL 워크플로우에 통합하면 배포 전에 문제를 사전에 차단할 수 있습니다. 또한 파일 생성 시점부터 인코딩과 포맷을 표준화하는 규약을 수립하면 장기적으로 유지보수 비용을 크게 줄일 수 있습니다.

“`sql

— 로딩 표준 템플릿 (팀 내 공유 문서로 관리)

— 반드시 FORMAT, DELIMITER, ENCODING, HEADER를 명시적으로 지정

COPY target_table FROM ‘/path/to/file.csv’

WITH (

FORMAT CSV,

DELIMITER ‘,’,

ENCODING ‘UTF8’,

HEADER true,

NULL ”

);

“`

  • 스테이징 테이블을 통한 단계적 데이터 검증

운영 테이블에 직접 COPY하지 말고, 동일한 구조의 스테이징(임시) 테이블에 먼저 데이터를 적재한 후 데이터 품질을 검증한 뒤 운영 테이블로 이동하는 2단계 프로세스를 사용하세요. 이 방식은 포맷 에러뿐만 아니라 데이터 타입 불일치, NULL 값 처리, 중복 데이터 등 다양한 문제를 운영 환경에 영향을 주지 않고 사전에 잡아낼 수 있습니다.

“`sql

— 스테이징 테이블 생성

CREATE TABLE employees_staging (LIKE employees);

— 스테이징에 먼저 로딩

COPY employees_staging FROM ‘/data/employees.csv’

WITH (FORMAT CSV, HEADER true, ENCODING ‘UTF8’);

— 데이터 검증

SELECT COUNT(*) FROM employees_staging;

SELECT * FROM employees_staging WHERE id IS NULL OR name IS NULL;

— 검증 통과 후 운영 테이블로 이동

INSERT INTO employees SELECT * FROM employees_staging;

— 스테이징 테이블 정리

TRUNCATE employees_staging;

“`


관련 에러

  • 22007 invalid_datetime_format: 날짜/시간 컬럼의 포맷이 맞지 않을 때 발생하며, CSV 파일의 날짜 형식이 PostgreSQL 설정(DateStyle)과 다를 때 자주 함께 나타납니다.
  • 22P05 untranslatable_character: 파일 인코딩 변환 과정에서 대상 인코딩으로 변환할 수 없는 문자가 존재할 때 발생합니다. 22P04와 함께 인코딩 문제에서 자주 발생합니다.
  • 42601 syntax_error: COPY 명령어 자체의 문법이 잘못된 경우 발생합니다. 옵션 이름이나 괄호 누락 등이 원인입니다.
  • 23502 not_null_violation: 파일 내 NULL 값 처리 설정이 맞지 않아 NOT NULL 제약 조건을 위반할 때 발생합니다. NULL '' 옵션 설정으로 대부분 해결됩니다.

DBMS 에러 코드 시리즈

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

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

댓글 남기기