2026년 10월 27일 | DBMS Error 가이드
이 글에서 다루는 내용
2203A 에러의 원인 분석, 해결 SQL, 예방 방법을 실무 관점에서 정리합니다.
2203A sql json member not found 는?
PostgreSQL 에러 코드 2203A는 JSON 경로(JSON Path) 쿼리 또는 SQL/JSON 함수를 사용할 때 요청한 멤버(키 또는 배열 인덱스)가 JSON 데이터 내에 존재하지 않을 경우 발생합니다. 예를 들어, jsonb_path_query, JSON_VALUE, JSON_QUERY, JSON_EXISTS 등의 함수에서 존재하지 않는 키를 접근하려 할 때 이 에러가 트리거됩니다. 특히 PostgreSQL 15 이상에서 도입된 SQL 표준 JSON 함수들(JSON_VALUE, JSON_QUERY 등)의 ERROR ON EMPTY 또는 ERROR ON ERROR 옵션이 활성화된 경우 자주 발생하는 에러입니다.
주요 발생 원인
- 존재하지 않는 JSON 키에 대한 접근
JSON 데이터에서 실제로 없는 키를 JSON Path 표현식으로 접근할 때 가장 흔하게 발생합니다. 예를 들어, {"name": "Alice"} 와 같은 JSON 객체에서 $.age 와 같이 존재하지 않는 멤버를 조회하면 이 에러가 발생합니다. 특히 데이터 소스가 다양하거나 스키마가 자유로운 경우, 일부 레코드에는 특정 키가 없을 수 있어 예상치 못한 에러로 이어집니다.
ERROR ON EMPTY옵션이 활성화된 SQL/JSON 함수 사용
PostgreSQL 15+에서 제공하는 JSON_VALUE, JSON_QUERY 함수는 결과가 없을 때 기본 동작(NULL ON EMPTY)을 명시적으로 ERROR ON EMPTY로 변경하면 해당 에러가 발생합니다. 개발자가 표준 SQL/JSON 함수를 처음 사용할 때 이 옵션의 의미를 제대로 인지하지 못하고 설정하는 경우가 많습니다. 이는 애플리케이션 레벨에서 제어되어야 할 예외 처리를 DB 레벨로 끌어올리게 되어 의도치 않은 트랜잭션 롤백을 유발할 수 있습니다.
- 동적으로 생성된 JSON Path 표현식의 오류
애플리케이션에서 사용자 입력이나 프로그래밍 로직에 의해 JSON Path 표현식이 동적으로 생성되는 경우, 키 이름의 오타 또는 잘못된 경로 구조로 인해 에러가 발생할 수 있습니다. 예를 들어, 대소문자 구분($.Name vs $.name)이나 중첩 구조의 경로($.address.city vs $.address.City)가 실제 데이터와 다를 때 에러가 트리거됩니다. 이러한 문제는 로그 분석 없이는 원인 파악이 어려워 운영 환경에서 디버깅 비용이 커집니다.
해결 방법
원인 1 해결: 키 존재 여부 사전 확인 후 접근
JSON 데이터에 접근하기 전에 해당 키가 존재하는지 먼저 확인하는 방식으로 에러를 방지할 수 있습니다.
-- 잘못된 예: 키가 없으면 에러 발생 가능
SELECT JSON_VALUE(data, '$.age' ERROR ON EMPTY)
FROM users;
-- 올바른 예: 키 존재 여부를 먼저 확인
SELECT
CASE
WHEN data ? 'age' THEN (data->>'age')::int
ELSE NULL
END AS age
FROM users;
-- JSON_EXISTS를 활용한 안전한 접근
SELECT
JSON_VALUE(data, '$.age' NULL ON EMPTY) AS age
FROM users
WHERE JSON_EXISTS(data, '$.age');
-- jsonb_path_exists를 활용한 방어적 쿼리
SELECT
id,
CASE
WHEN jsonb_path_exists(data, '$.address.city')
THEN jsonb_path_query_first(data, '$.address.city') #>> '{}'
ELSE '주소 없음'
END AS city
FROM customers;
원인 2 해결: NULL ON EMPTY 옵션 사용 또는 기본값 처리
ERROR ON EMPTY 대신 NULL ON EMPTY를 사용하거나 DEFAULT ... ON EMPTY로 기본값을 제공하면 에러 없이 처리할 수 있습니다.
-- PostgreSQL 15+ SQL/JSON 함수에서 안전하게 사용하는 방법
-- NULL ON EMPTY: 멤버가 없으면 NULL 반환 (기본값)
SELECT JSON_VALUE(data, '$.email' NULL ON EMPTY) AS email
FROM users;
-- DEFAULT ON EMPTY: 멤버가 없으면 기본값 반환
SELECT JSON_VALUE(data, '$.phone' DEFAULT 'N/A' ON EMPTY) AS phone
FROM users;
-- NULL ON EMPTY, NULL ON ERROR: 에러와 빈 결과 모두 NULL로 처리
SELECT JSON_VALUE(
data,
'$.profile.age'
NULL ON EMPTY
NULL ON ERROR
) AS age
FROM users;
-- COALESCE와 함께 활용
SELECT
COALESCE(
JSON_VALUE(data, '$.nickname' NULL ON EMPTY),
JSON_VALUE(data, '$.name' NULL ON EMPTY),
'익명'
) AS display_name
FROM users;
원인 3 해결: JSON Path 표현식 검증 및 안전한 함수 래핑
동적으로 생성된 경로에 대한 안전장치를 마련하고, 예외 처리를 명시적으로 구현합니다.
-- jsonb_path_query_first를 사용하면 결과가 없어도 NULL 반환 (에러 없음)
SELECT
id,
jsonb_path_query_first(data, '$.address.city') AS city,
jsonb_path_query_first(data, '$.address.zipcode') AS zipcode
FROM customers;
-- 실제 JSON 데이터 구조 확인용 쿼리 (디버깅)
SELECT DISTINCT jsonb_object_keys(data) AS top_level_keys
FROM users
LIMIT 50;
-- 중첩 구조 키 확인
SELECT DISTINCT jsonb_object_keys(data->'address') AS address_keys
FROM users
WHERE data ? 'address'
LIMIT 50;
-- 안전한 동적 JSON 경로 처리를 위한 함수 작성
CREATE OR REPLACE FUNCTION safe_json_value(
p_data jsonb,
p_path text,
p_default text DEFAULT NULL
) RETURNS text AS $$
BEGIN
RETURN jsonb_path_query_first(p_data, p_path::jsonpath) #>> '{}';
EXCEPTION
WHEN SQLSTATE '2203A' THEN
RETURN p_default;
WHEN OTHERS THEN
RETURN p_default;
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- 함수 사용 예시
SELECT
id,
safe_json_value(data, '$.name', '이름 없음') AS name,
safe_json_value(data, '$.age', '0') AS age,
safe_json_value(data, '$.address.city', '도시 미상') AS city
FROM users;
예방 방법
- JSON 데이터 입력 시 스키마 검증 적용
JSON 데이터가 데이터베이스에 저장될 때 CHECK 제약 조건 또는 트리거를 통해 필수 키의 존재 여부를 검증하면, 이후 조회 시 발생할 수 있는 2203A 에러를 근본적으로 예방할 수 있습니다. PostgreSQL의 jsonb_schema_valid() 함수(pg_jsonschema 확장)나 CHECK 제약 조건을 활용해 필수 필드를 강제하는 것이 바람직합니다.
“`sql
— CHECK 제약 조건으로 필수 키 보장
ALTER TABLE users
ADD CONSTRAINT chk_required_json_keys
CHECK (
data ? ‘name’ AND data ? ’email’
);
— pg_jsonschema 확장을 사용한 JSON Schema 검증 (권장)
— CREATE EXTENSION pg_jsonschema;
ALTER TABLE users
ADD CONSTRAINT chk_json_schema
CHECK (
jsonb_matches_schema(
‘{
“type”: “object”,
“required”: [“name”, “email”],
“properties”: {
“name”: {“type”: “string”},
“email”: {“type”: “string”},
“age”: {“type”: “integer”}
}
}’,
data
)
);
“`
- SQL/JSON 함수 사용 시 항상
NULL ON EMPTY및NULL ON ERROR명시
팀 내 코딩 표준으로 JSON_VALUE, JSON_QUERY 함수 사용 시 항상 NULL ON EMPTY NULL ON ERROR 옵션을 명시하도록 규칙을 정하면, 예상치 못한 에러로 인한 장애를 예방할 수 있습니다. 코드 리뷰 체크리스트에 이 항목을 포함시키거나, 린트 도구를 활용해 ERROR ON EMPTY나 ERROR ON ERROR 옵션의 사용을 경고하도록 설정하는 것도 좋은 방법입니다.
“`sql
— 팀 표준: 항상 NULL ON EMPTY NULL ON ERROR 명시
SELECT
JSON_VALUE(payload, ‘$.user.id’ NULL ON EMPTY NULL ON ERROR) AS user_id,
JSON_VALUE(payload, ‘$.user.name’ NULL ON EMPTY NULL ON ERROR) AS user_name,
JSON_VALUE(payload, ‘$.event.type’ NULL ON EMPTY NULL ON ERROR) AS event_type
FROM event_log;
“`
관련 에러
22032(invalid_json_text): JSON 형식 자체가 잘못된 경우 발생하며,2203A와 함께 JSON 처리 오류의 쌍벽을 이룹니다.22033(invalid_sql_json_subscript): JSON 배열에서 유효하지 않은 인덱스를 사용할 때 발생합니다.22034(more_than_one_sql_json_item):JSON_VALUE와 같이 단일 값을 기대하는 함수에서 복수의 결과가 반환될 때 발생합니다.22035(no_sql_json_item): JSON Path 표현식이 어떤 항목도 선택하지 못했을 때 발생하며,2203A와 혼동하기 쉬운 에러입니다.22036(non_numeric_sql_json_item): 숫자형 연산에 비숫자 JSON 값이 사용될 때 발생합니다.
주요 DBMS error code를 정리하는 시리즈입니다.
블로그 홈에서 다른 에러도 확인하세요.
본 포스트는 AI가 생성한 기술 가이드입니다. 운영 환경 적용 전 충분한 검토를 권장합니다.