2026년 08월 23일 | DBMS Error 가이드
이 글에서 다루는 내용
2203C 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2203C sql json object not found 는?
PostgreSQL 에러 코드 2203C는 SQL/JSON 경로 표현식을 사용할 때 대상 JSON 데이터에서 지정한 경로나 키에 해당하는 객체를 찾지 못했을 때 발생하는 에러입니다. 주로 JSON_TABLE, JSON_VALUE, JSON_QUERY, JSON_EXISTS 등의 SQL/JSON 함수에서 경로 표현식이 존재하지 않는 키나 배열 인덱스를 참조할 때 나타납니다. 이 에러는 PostgreSQL 16 이상에서 ISO SQL 표준을 따르는 SQL/JSON 함수가 도입되면서 더욱 빈번하게 접하게 되는 에러로, JSON 데이터 구조에 대한 정확한 이해가 필요합니다.
주요 발생 원인
1. 존재하지 않는 JSON 키를 ERROR ON EMPTY 모드에서 참조하는 경우
SQL/JSON 함수에서 기본 동작 또는 ERROR ON EMPTY 옵션을 명시적으로 지정한 상태에서 존재하지 않는 키를 조회하면 이 에러가 발생합니다. 예를 들어 JSON_VALUE 함수에서 존재하지 않는 키를 경로로 지정하고 ERROR ON EMPTY 절을 사용하면 해당 키가 없을 때 즉시 에러를 던집니다. 실무에서 JSON 스키마가 유연하게 변하는 경우 특히 자주 발생하며, 항상 모든 키가 존재한다는 가정 하에 쿼리를 작성할 때 문제가 됩니다.
2. 잘못된 JSON 경로 표현식(JSONPath)으로 인한 참조 실패
JSONPath 표현식에서 오타, 잘못된 배열 인덱스, 또는 잘못된 중첩 경로를 사용할 경우 대상 객체를 찾지 못해 에러가 발생합니다. 예를 들어 $.address.city 경로를 지정했지만 실제 JSON에는 $.addr.city로 저장되어 있거나, $.items[5]를 참조했지만 배열의 원소가 3개뿐인 경우가 이에 해당합니다. 특히 JSON 데이터를 외부 시스템에서 수신하는 경우 스키마 변경이 잦아 이런 문제가 더욱 빈번하게 발생합니다.
3. JSON_TABLE 사용 시 NESTED PATH에서 대응하는 객체 부재
JSON_TABLE 함수의 NESTED PATH 절을 사용할 때 중첩된 경로에 해당하는 배열이나 객체가 일부 행에 존재하지 않으면 에러가 발생할 수 있습니다. JSON 데이터가 완전히 균일하지 않은 경우, 즉 일부 레코드에는 특정 중첩 객체가 없는 경우 쿼리 전체가 실패하게 됩니다. 이런 상황은 실무에서 이기종 JSON 데이터를 관계형 테이블로 변환할 때 매우 흔하게 발생합니다.
해결 방법
원인 1 해결: ERROR ON EMPTY 대신 DEFAULT 또는 NULL ON EMPTY 사용
존재하지 않는 키에 접근할 때 에러 대신 NULL이나 기본값을 반환하도록 옵션을 변경합니다.
-- 에러 발생 예시 (ERROR ON EMPTY 명시)
SELECT JSON_VALUE(
'{"name": "Alice"}'::json,
'$.age'
ERROR ON EMPTY
);
-- ERROR: SQL/JSON object not found
-- 해결 방법 1: NULL ON EMPTY 사용
SELECT JSON_VALUE(
'{"name": "Alice"}'::json,
'$.age'
NULL ON EMPTY
) AS age;
-- 결과: NULL
-- 해결 방법 2: DEFAULT 값 지정
SELECT JSON_VALUE(
'{"name": "Alice"}'::json,
'$.age'
DEFAULT '0' ON EMPTY
) AS age;
-- 결과: 0
-- 실무 예시: 테이블 컬럼에 적용
SELECT
id,
JSON_VALUE(data, '$.user.name' NULL ON EMPTY) AS user_name,
JSON_VALUE(data, '$.user.email' DEFAULT 'N/A' ON EMPTY) AS user_email
FROM user_events;
원인 2 해결: JSONPath 표현식 검증 후 사용
쿼리 실행 전 JSON_EXISTS를 사용하여 경로 존재 여부를 먼저 확인합니다.
-- JSON 경로 존재 여부 먼저 확인
SELECT
id,
JSON_EXISTS(data, '$.address.city') AS has_city,
CASE
WHEN JSON_EXISTS(data, '$.address.city')
THEN JSON_VALUE(data, '$.address.city')
ELSE '정보 없음'
END AS city
FROM customers;
-- JSON_QUERY로 안전하게 객체 전체 추출
SELECT JSON_QUERY(
'{"user": {"name": "Bob"}}'::jsonb,
'$.user.address'
NULL ON EMPTY
) AS address;
-- 결과: NULL (에러 없이 처리)
-- 배열 인덱스 안전 접근
SELECT JSON_VALUE(
'{"items": [1, 2, 3]}'::json,
'$.items[10]'
NULL ON EMPTY
) AS tenth_item;
-- 결과: NULL
-- jsonb 연산자를 활용한 안전한 키 접근 (기존 방식과 병행)
SELECT
data -> 'address' ->> 'city' AS city,
data #>> '{user,profile,avatar}' AS avatar
FROM users
WHERE data ? 'address';
원인 3 해결: JSON_TABLE의 NESTED PATH에 안전 처리 추가
-- 문제가 발생하는 쿼리 예시
SELECT jt.*
FROM orders,
JSON_TABLE(
order_data,
'$'
COLUMNS (
order_id INT PATH '$.id',
NESTED PATH '$.items[*]'
COLUMNS (
item_name TEXT PATH '$.name',
quantity INT PATH '$.qty' ERROR ON EMPTY
)
)
) AS jt;
-- 해결: NULL ON EMPTY와 NULL ON ERROR 적용
SELECT jt.*
FROM orders,
JSON_TABLE(
order_data,
'$'
COLUMNS (
order_id INT PATH '$.id' NULL ON EMPTY NULL ON ERROR,
NESTED PATH '$.items[*]'
COLUMNS (
item_name TEXT PATH '$.name' NULL ON EMPTY,
quantity INT PATH '$.qty' DEFAULT 1 ON EMPTY NULL ON ERROR
)
)
) AS jt;
-- 사전 필터링으로 불완전한 JSON 행 제외
SELECT jt.*
FROM orders,
JSON_TABLE(
order_data,
'$'
COLUMNS (
order_id INT PATH '$.id',
NESTED PATH '$.items[*]'
COLUMNS (
item_name TEXT PATH '$.name' NULL ON EMPTY,
quantity INT PATH '$.qty' NULL ON EMPTY
)
)
) AS jt
WHERE JSON_EXISTS(order_data, '$.items');
예방 방법
1. JSON 데이터 수신 시점에 스키마 검증 함수를 적용하라
운영 환경에서는 외부에서 유입되는 JSON 데이터를 저장하기 전에 필수 키의 존재 여부와 타입을 검증하는 트리거 또는 CHECK 제약조건을 설정해 두는 것이 좋습니다. 아래와 같이 JSON 스키마 검증을 위한 함수를 작성하고 이를 INSERT/UPDATE 트리거에 연결하면, 불완전한 JSON이 저장되는 것을 사전에 방지할 수 있습니다.
-- JSON 필수 키 검증 함수 생성
CREATE OR REPLACE FUNCTION validate_user_json(data jsonb)
RETURNS BOOLEAN AS $$
BEGIN
IF NOT (data ? 'id' AND data ? 'name' AND data ? 'email') THEN
RAISE EXCEPTION 'JSON 필수 키(id, name, email)가 없습니다: %', data;
END IF;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;
-- CHECK 제약조건으로 적용
ALTER TABLE user_events
ADD CONSTRAINT chk_user_json_schema
CHECK (validate_user_json(data));
2. SQL/JSON 함수 사용 시 항상 ON EMPTY / ON ERROR 절을 명시적으로 작성하라
암묵적인 기본 동작에 의존하지 말고, 쿼리 작성 시 NULL ON EMPTY, DEFAULT ... ON EMPTY, NULL ON ERROR 등을 반드시 명시적으로 작성하는 코딩 컨벤션을 팀 내에 도입하세요. 이렇게 하면 JSON 구조가 변경되더라도 쿼리가 예기치 않게 실패하는 상황을 예방할 수 있으며, 코드 리뷰 시에도 의도를 명확하게 전달할 수 있습니다.
관련 에러
2203F(sql_json_array_not_found): JSON 경로가 배열을 기대하지만 해당 위치에 배열이 없을 때 발생하며,2203C와 함께 JSON_TABLE의 NESTED PATH 절에서 자주 동반됩니다.2203G(sql_json_scalar_required): JSON 경로가 스칼라 값을 반환해야 하는 문맥에서 객체나 배열이 반환될 때 발생합니다.JSON_VALUE사용 시 경로가 단일 값이 아닌 복합 타입을 가리킬 때 나타납니다.22032(invalid_json_text): JSON 자체가 올바른 형식이 아닐 때 발생하는 파싱 에러로,2203C이전에 먼저 확인해야 할 에러입니다.2203D(sql_json_member_not_found): 객체에서 특정 멤버(키)를 찾지 못할 때 발생하며,2203C와 매우 유사한 상황에서 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.