2026년 09월 07일 | DBMS Error 가이드
이 글에서 다루는 내용
42846 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
42846 cannot coerce 는?
PostgreSQL 에러 코드 42846 (cannot coerce)는 특정 데이터 타입을 다른 타입으로 자동 또는 명시적으로 변환(캐스팅)할 수 없을 때 발생하는 타입 강제 변환 오류입니다. 예를 들어 integer 타입의 값을 boolean 타입으로 직접 변환하려 하거나, 서로 호환되지 않는 복합 타입 간의 캐스팅을 시도할 때 이 에러가 나타납니다. 주로 함수 호출, 연산자 사용, INSERT/UPDATE 구문, 또는 명시적 CAST 표현식에서 발생하며, PostgreSQL의 타입 시스템이 해당 변환 경로를 지원하지 않는다는 의미입니다.
주요 발생 원인
1. 호환되지 않는 타입 간의 명시적 CAST 시도
가장 흔한 원인으로, PostgreSQL 내부 캐스트 카탈로그(pg_cast)에 해당 타입 쌍에 대한 변환 규칙이 등록되어 있지 않은 경우입니다. 예를 들어 integer를 직접 boolean으로 CAST하거나, json 타입을 uuid 타입으로 직접 변환하는 것처럼 PostgreSQL이 기본적으로 지원하지 않는 타입 변환 경로를 사용할 때 발생합니다. 이 경우 중간 타입을 거쳐 변환하거나 별도의 커스텀 캐스트를 등록해야 합니다.
2. 복합 타입(Composite Type) 또는 도메인 타입 간의 부적절한 변환
사용자 정의 복합 타입(composite type)이나 도메인(domain) 타입 간의 캐스팅을 시도할 때 발생합니다. 두 타입의 구조가 논리적으로 유사하더라도 PostgreSQL은 명시적인 캐스트 함수나 캐스트 규칙이 없으면 변환을 허용하지 않습니다. 특히 ORM 프레임워크나 마이그레이션 도구가 내부적으로 타입 변환을 수행할 때 예상치 못하게 이 에러가 발생할 수 있습니다.
3. 함수 또는 연산자의 인자 타입 불일치로 인한 암묵적 캐스팅 실패
PostgreSQL은 함수나 연산자를 호출할 때 인자의 타입이 정확히 일치하지 않으면 내부적으로 암묵적 캐스팅(implicit cast)을 시도합니다. 그러나 해당 타입 쌍에 대해 implicit 또는 assignment 레벨의 캐스트가 정의되어 있지 않으면 42846 에러가 발생합니다. 예를 들어 text 타입을 받는 함수에 xml 타입의 값을 그대로 전달하는 경우가 이에 해당합니다.
해결 방법
원인 1 해결: 중간 타입을 경유한 명시적 변환
직접 변환이 불가능한 경우, text나 varchar와 같은 중간 타입을 거쳐 단계적으로 변환합니다.
-- 잘못된 예: integer를 boolean으로 직접 캐스팅 (42846 발생)
SELECT CAST(1 AS boolean);
-- 올바른 예: text를 중간 단계로 사용
SELECT CAST(CAST(1 AS text) AS boolean);
-- 또는 조건식을 사용하여 논리적으로 처리
SELECT CASE WHEN 1 = 0 THEN false ELSE true END AS result;
-- json 타입을 uuid로 변환할 때 text 경유
SELECT CAST(json_data->>'user_id' AS uuid)
FROM user_events
WHERE event_type = 'login';
원인 2 해결: 커스텀 캐스트 함수 등록
복합 타입 간 변환이 필요한 경우, 변환 함수를 작성하고 CREATE CAST로 등록합니다.
-- 예시: 두 도메인 타입 간의 커스텀 캐스트 등록
CREATE DOMAIN positive_int AS integer CHECK (VALUE > 0);
CREATE DOMAIN score_int AS integer CHECK (VALUE BETWEEN 0 AND 100);
-- 변환 함수 작성
CREATE OR REPLACE FUNCTION positive_int_to_score(positive_int)
RETURNS score_int AS $$
SELECT CASE
WHEN $1 > 100 THEN 100::score_int
ELSE $1::score_int
END;
$$ LANGUAGE sql STRICT IMMUTABLE;
-- 커스텀 캐스트 등록 (명시적 캐스트로 등록)
CREATE CAST (positive_int AS score_int)
WITH FUNCTION positive_int_to_score(positive_int)
AS ASSIGNMENT;
-- 이제 아래 변환이 정상적으로 동작함
SELECT CAST(95::positive_int AS score_int);
원인 3 해결: 함수 호출 시 명시적 타입 변환 적용
함수나 연산자 호출 시 인자를 명시적으로 변환하여 암묵적 캐스팅에 의존하지 않도록 합니다.
-- 잘못된 예: xml 타입을 text 함수에 직접 전달
SELECT length(xml_column) FROM documents; -- 42846 발생 가능
-- 올바른 예: xmlserialize 또는 명시적 캐스트 사용
SELECT length(xmlserialize(content xml_column AS text))
FROM documents;
-- 또는 명시적 CAST 사용
SELECT length(CAST(xml_column AS text))
FROM documents;
-- 실무 예: 혼합 타입이 들어오는 컬럼 처리
UPDATE products
SET price = CAST(raw_price_text AS numeric(10,2))
WHERE raw_price_text ~ '^\d+(\.\d+)?$'; -- 숫자 형식인 경우만 변환
-- pg_cast 카탈로그에서 지원되는 캐스트 경로 조회
SELECT
pg_type.typname AS source_type,
target.typname AS target_type,
pg_cast.castcontext AS cast_context
FROM pg_cast
JOIN pg_type ON pg_type.oid = pg_cast.castsource
JOIN pg_type AS target ON target.oid = pg_cast.casttarget
WHERE pg_type.typname = 'xml'
ORDER BY target_type;
원인 1~3 공통: 에러 발생 지점 디버깅
-- 현재 세션에서 발생하는 캐스팅 관련 상세 로그 확인
SET client_min_messages = 'DEBUG5';
-- 특정 컬럼의 타입 확인
SELECT
column_name,
data_type,
udt_name
FROM information_schema.columns
WHERE table_name = 'your_table'
AND table_schema = 'public';
-- 타입 OID로 pg_cast에서 변환 가능 여부 조회
SELECT EXISTS (
SELECT 1 FROM pg_cast
WHERE castsource = 'integer'::regtype
AND casttarget = 'boolean'::regtype
) AS cast_exists;
예방 방법
1. 데이터 모델 설계 단계에서 타입 일관성 확보
테이블 설계 초기부터 컬럼 간, 테이블 간 데이터 타입의 일관성을 확보하는 것이 가장 효과적인 예방책입니다. 특히 외래 키(FK) 관계에 있는 컬럼은 동일한 타입을 사용하고, 도메인 타입을 적극 활용하여 비즈니스 규칙을 타입 수준에서 강제하면 캐스팅 오류를 미연에 방지할 수 있습니다. 코드 리뷰 시 SQL 쿼리에서 암묵적 타입 변환이 발생하는지 반드시 점검하는 습관을 들이세요.
-- 좋은 예: 공통 도메인 타입 사용으로 타입 일관성 확보
CREATE DOMAIN user_id_t AS uuid NOT NULL;
CREATE TABLE users (
id user_id_t DEFAULT gen_random_uuid() PRIMARY KEY,
email text NOT NULL
);
CREATE TABLE orders (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
user_id user_id_t REFERENCES users(id), -- 동일 도메인 타입 사용
total numeric(12,2) NOT NULL
);
2. pg_cast 카탈로그를 활용한 사전 변환 가능성 검증
운영 환경에 쿼리를 배포하기 전, 개발/스테이징 환경에서 pg_cast 카탈로그를 통해 변환 가능 여부를 사전에 검증하는 절차를 CI/CD 파이프라인에 포함시키세요. 또한 애플리케이션 레벨에서는 데이터베이스에 값을 전달하기 전에 타입을 명확히 지정하고, ORM을 사용하는 경우 타입 매핑 설정이 올바른지 정기적으로 검토해야 합니다.
-- 배포 전 검증 쿼리: 특정 타입 쌍의 캐스트 경로와 컨텍스트 확인
SELECT
src.typname AS from_type,
tgt.typname AS to_type,
c.castcontext AS context, -- 'e'=explicit, 'a'=assignment, 'i'=implicit
CASE c.castmethod
WHEN 'f' THEN 'function'
WHEN 'i' THEN 'io conversion'
WHEN 'b' THEN 'binary coercible'
END AS method
FROM pg_cast c
JOIN pg_type src ON src.oid = c.castsource
JOIN pg_type tgt ON tgt.oid = c.casttarget
WHERE src.typname IN ('text', 'varchar', 'integer', 'numeric', 'uuid', 'json', 'jsonb')
ORDER BY from_type, to_type;
관련 에러
- 42883 (undefined_function): 함수 오버로드가 없어서 주어진 인자 타입에 맞는 함수를 찾지 못할 때 발생하며, 42846과 함께 나타나는 경우가 많습니다.
- 42804 (datatype_mismatch): 두 표현식의 타입이 일치해야 하는 상황(예: UNION, CASE 표현식)에서 타입이 다를 때 발생하는 에러로, cannot coerce와 혼동하기 쉽습니다.
- 22P02 (invalid_text_representation): 텍스트를 특정 타입으로 변환할 때 형식이 올바르지 않아 런타임에 발생하는 에러로, 캐스팅 시도는 성공했지만 값 자체가 유효하지 않은 경우입니다.
- 42P18 (indeterminate_datatype): 표현식의 타입을 결정할 수 없을 때 발생하며, 주로 파라미터 타입이 불명확한 경우에 나타납니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.