PostgreSQL 2203G 오류 원인과 해결 방법 완벽 가이드

2203G
2026년 08월 24일 | DBMS Error 가이드

이 글에서 다루는 내용

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

2203G sql json item cannot be cast to target type 는?

PostgreSQL 에러 코드 2203G는 SQL/JSON 경로 표현식이나 JSON 함수를 사용할 때, JSON 데이터의 특정 항목을 지정한 대상 타입으로 형변환(cast)할 수 없을 때 발생합니다. 예를 들어 JSON 배열 안에 문자열로 저장된 값을 integerdate 같은 타입으로 직접 변환하려 할 때 이 에러가 나타납니다. 주로 JSON_VALUE(), JSON_QUERY(), JSON_TABLE() 같은 SQL 표준 JSON 함수나 jsonpath 연산자를 사용하는 환경에서 자주 마주치게 됩니다.


주요 발생 원인

  • JSON 값의 실제 타입과 목표 타입 불일치

가장 흔한 원인입니다. JSON 내부에 "2024-01-15" 처럼 문자열 형태로 저장된 날짜 값을 RETURNING date 옵션으로 바로 추출하려 하거나, "abc"처럼 숫자가 아닌 문자열을 RETURNING integer로 변환하려 할 때 발생합니다. PostgreSQL의 SQL/JSON 함수는 내부적으로 엄격한 타입 검사를 수행하며, 묵시적 변환이 불가능한 경우 즉시 에러를 반환합니다.

  • JSON 숫자 값의 범위 초과 또는 정밀도 문제

JSON 표준에서 숫자는 무제한 정밀도를 가질 수 있지만, PostgreSQL의 integer, smallint, real 등은 각각 고유한 범위와 정밀도 제한을 가집니다. JSON에 9999999999999999999처럼 큰 숫자가 저장되어 있을 때 이를 integer로 추출하면 범위를 초과하여 형변환이 불가능해집니다. 또한 1.99999999999999999처럼 부동소수점 정밀도를 초과하는 값도 특정 타입으로의 변환 시 이 에러를 일으킬 수 있습니다.

  • JSON 배열 또는 객체를 스칼라 타입으로 변환 시도

JSON_VALUE() 함수는 스칼라 값만 반환할 수 있도록 설계되어 있습니다. 그런데 jsonpath 표현식이 배열([1,2,3])이나 객체({"a":1}) 전체를 가리키게 되면, 이를 textinteger 같은 스칼라 타입으로 변환하는 것이 불가능하여 2203G 에러가 발생합니다. 특히 중첩 구조가 복잡한 JSON을 다룰 때 경로 표현식 실수로 인해 자주 발생합니다.


해결 방법

원인 1 해결: 타입 불일치 — 명시적 캐스팅 또는 경로 수정

형변환이 불가능한 경우, JSON_VALUE()에서 먼저 text로 추출한 후 애플리케이션 단에서 처리하거나, PostgreSQL의 명시적 캐스팅을 활용합니다.

-- 에러 발생 예시: 문자열 날짜를 RETURNING date로 직접 추출
SELECT JSON_VALUE(
    '{"order_date": "2024-01-15"}'::jsonb,
    '$.order_date' RETURNING date
);
-- ERROR: sql json item cannot be cast to target type (2203G)

-- 해결 방법 1: 먼저 text로 추출 후 명시적 캐스팅
SELECT JSON_VALUE(
    '{"order_date": "2024-01-15"}'::jsonb,
    '$.order_date' RETURNING text
)::date;
-- 결과: 2024-01-15

-- 해결 방법 2: ->> 연산자로 텍스트 추출 후 캐스팅 (jsonb 기준)
SELECT (
    '{"order_date": "2024-01-15"}'::jsonb ->> 'order_date'
)::date;
-- 결과: 2024-01-15

-- 해결 방법 3: ON ERROR 절 활용 (에러를 NULL로 처리)
SELECT JSON_VALUE(
    '{"order_date": "not-a-date"}'::jsonb,
    '$.order_date' RETURNING date
    NULL ON ERROR
);
-- 결과: NULL (에러 대신 NULL 반환)

원인 2 해결: 숫자 범위 초과 — 더 큰 타입 사용

-- 에러 발생 예시: 큰 숫자를 integer로 변환
SELECT JSON_VALUE(
    '{"user_id": 9999999999}'::jsonb,
    '$.user_id' RETURNING integer
);
-- ERROR: sql json item cannot be cast to target type (2203G)

-- 해결 방법 1: bigint 사용
SELECT JSON_VALUE(
    '{"user_id": 9999999999}'::jsonb,
    '$.user_id' RETURNING bigint
);
-- 결과: 9999999999

-- 해결 방법 2: numeric으로 정밀도 손실 없이 처리
SELECT JSON_VALUE(
    '{"amount": 1.99999999999999999}'::jsonb,
    '$.amount' RETURNING numeric
);
-- 결과: 2.00000000000000000 (numeric 정밀도 내에서 처리)

-- 데이터 타입 범위 확인 쿼리
SELECT
    (data->>'value')::text AS raw_value,
    CASE
        WHEN (data->>'value')::numeric BETWEEN -2147483648 AND 2147483647
            THEN 'integer 사용 가능'
        WHEN (data->>'value')::numeric BETWEEN -9223372036854775808 AND 9223372036854775807
            THEN 'bigint 사용 가능'
        ELSE 'numeric 사용 필요'
    END AS recommended_type
FROM (VALUES ('{"value": 9999999999}'::jsonb)) AS t(data);

원인 3 해결: 배열/객체를 스칼라로 변환 시도

-- 에러 발생 예시: 배열 전체를 text로 추출 시도
SELECT JSON_VALUE(
    '{"tags": ["postgresql", "database", "sql"]}'::jsonb,
    '$.tags' RETURNING text
);
-- ERROR: sql json item cannot be cast to target type (2203G)

-- 해결 방법 1: JSON_QUERY() 사용 (배열/객체 반환에 적합)
SELECT JSON_QUERY(
    '{"tags": ["postgresql", "database", "sql"]}'::jsonb,
    '$.tags'
);
-- 결과: ["postgresql", "database", "sql"]

-- 해결 방법 2: 특정 인덱스 원소만 추출
SELECT JSON_VALUE(
    '{"tags": ["postgresql", "database", "sql"]}'::jsonb,
    '$.tags[0]' RETURNING text
);
-- 결과: postgresql

-- 해결 방법 3: JSON_TABLE()로 배열을 행으로 펼치기
SELECT tag
FROM JSON_TABLE(
    '{"tags": ["postgresql", "database", "sql"]}'::jsonb,
    '$.tags[*]'
    COLUMNS (tag text PATH '$')
) AS jt;
-- 결과:
-- tag
-- -----------
-- postgresql
-- database
-- sql

-- 해결 방법 4: jsonb_array_elements_text() 활용 (기존 방식)
SELECT value AS tag
FROM jsonb_array_elements_text(
    '["postgresql", "database", "sql"]'::jsonb
);

예방 방법

  • JSON 데이터 입력 단계에서 스키마 검증 적용

JSON 데이터가 데이터베이스에 저장되기 전에 애플리케이션 레벨 또는 PostgreSQL의 CHECK 제약 조건을 활용해 형식과 타입을 검증하세요. 이를 통해 잘못된 타입의 데이터가 저장되는 것을 원천 차단할 수 있습니다.

“`sql

— CHECK 제약으로 JSON 필드 타입 검증

CREATE TABLE orders (

id serial PRIMARY KEY,

data jsonb NOT NULL,

CONSTRAINT chk_order_date_format CHECK (

(data->>’order_date’) IS NULL OR

(data->>’order_date’)::text ~ ‘^\d{4}-\d{2}-\d{2}$’

),

CONSTRAINT chk_amount_numeric CHECK (

(data->>’amount’) IS NULL OR

(data->>’amount’) ~ ‘^[0-9]+(\.[0-9]+)?$’

)

);

“`

  • ON ERROR 절과 방어적 쿼리 패턴 사용 습관화

SQL/JSON 함수를 사용할 때는 항상 ON ERROR 절을 명시하여 예기치 않은 형변환 에러를 제어된 방식으로 처리하고, 로그나 모니터링 시스템에 기록하는 패턴을 팀 표준으로 정착시키세요.

“`sql

— ON ERROR 절을 활용한 방어적 패턴

SELECT

id,

JSON_VALUE(data, ‘$.amount’ RETURNING numeric NULL ON ERROR) AS amount,

JSON_VALUE(data, ‘$.order_date’ RETURNING date NULL ON ERROR) AS order_date,

JSON_VALUE(data, ‘$.user_id’ RETURNING bigint NULL ON ERROR) AS user_id

FROM orders

WHERE id = 1;

“`


관련 에러

  • 2203F (invalid SQL JSON subscript): JSON 배열 인덱스가 잘못된 형식이거나 범위를 벗어났을 때 발생합니다.
  • 2203W (SQL JSON array not found): jsonpath 표현식이 배열을 기대하는데 해당 경로에 배열이 없을 때 발생합니다.
  • 22023 (invalid_parameter_value): JSON 함수에 잘못된 파라미터가 전달될 때 나타나며, 2203G와 혼동하기 쉽습니다.
  • 22P02 (invalid_text_representation): JSON 문자열 자체가 유효하지 않은 형식일 때 발생하며, 파싱 단계에서 실패합니다. 2203G는 파싱 이후 타입 변환 단계에서 실패한다는 점에서 차이가 있습니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기