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

22035
2026년 10월 25일 | DBMS Error 가이드

이 글에서 다루는 내용

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

22035 no sql json item 는?

PostgreSQL 에러 코드 22035는 no sql json item이라는 메시지와 함께 발생하며, SQL/JSON 경로 표현식(JSON Path Expression)을 사용할 때 해당 경로가 아무런 JSON 아이템도 반환하지 못할 경우 발생하는 에러입니다. 이 에러는 주로 jsonb_path_query, jsonb_path_value, JSON_VALUE, JSON_QUERY 등의 함수에서 엄격 모드(strict mode)를 사용하거나, 결과가 반드시 존재해야 한다는 조건 하에 JSON 데이터를 조회할 때 나타납니다. 즉, JSON 문서 안에서 지정한 경로에 해당하는 데이터가 존재하지 않을 때 PostgreSQL이 이 에러를 던지며, 이는 데이터 품질 문제나 잘못된 경로 표현식으로 인해 실무에서 빈번히 마주치는 에러 중 하나입니다.


주요 발생 원인

1. 존재하지 않는 JSON 경로를 strict 모드에서 조회하는 경우

JSON Path 표현식에는 lax 모드와 strict 모드가 존재합니다. lax 모드는 경로가 존재하지 않더라도 빈 시퀀스를 반환하고 에러를 발생시키지 않지만, strict 모드에서는 경로에 해당하는 아이템이 없으면 즉시 에러를 발생시킵니다. 특히 JSON_VALUE 함수의 기본 동작이나 jsonb_path_value 함수에서 strict 키워드를 명시적으로 사용할 때, JSON 데이터에 해당 키가 없는 경우 22035 에러가 발생하게 됩니다.

-- 에러 발생 예시: strict 모드에서 존재하지 않는 키 조회
SELECT jsonb_path_value(
    '{"name": "Alice"}'::jsonb,
    'strict $.age'
);
-- ERROR: no SQL/JSON item

2. 배열 인덱스가 범위를 벗어나는 경우

JSON 배열을 다룰 때, 존재하지 않는 인덱스를 strict 모드에서 접근하려 하면 동일한 에러가 발생합니다. 예를 들어 3개의 요소를 가진 배열에서 인덱스 10번 요소를 strict 모드로 조회하면 해당 아이템이 존재하지 않기 때문에 no sql json item 에러가 발생합니다. 이 경우는 배열의 크기를 사전에 확인하지 않고 고정 인덱스를 사용하는 코드에서 자주 발생합니다.

-- 에러 발생 예시: 범위를 벗어난 배열 인덱스
SELECT jsonb_path_value(
    '[1, 2, 3]'::jsonb,
    'strict $[10]'
);
-- ERROR: no SQL/JSON item

-- lax 모드에서는 NULL 반환 (에러 없음)
SELECT jsonb_path_value(
    '[1, 2, 3]'::jsonb,
    'lax $[10]'
);
-- 결과: NULL

3. JSON_VALUE / JSON_QUERY에서 ERROR ON EMPTY 옵션 지정 시

PostgreSQL 16 이상에서 지원되는 SQL 표준 JSON_VALUE, JSON_QUERY 함수에서 ERROR ON EMPTY 옵션을 명시적으로 지정한 경우, 결과가 없으면 22035 에러가 발생합니다. 이 옵션은 경로 표현식이 아무런 결과도 반환하지 않을 때의 동작을 제어하며, 기본값(NULL ON EMPTY)과 달리 에러를 던지도록 설정된 경우 예상치 못한 상황에서 애플리케이션이 중단될 수 있습니다.

-- ERROR ON EMPTY 옵션으로 인한 에러 발생
SELECT JSON_VALUE(
    '{"name": "Alice"}'::json,
    '$.age'
    ERROR ON EMPTY
);
-- ERROR: no SQL/JSON item

-- 안전한 방식: DEFAULT ON EMPTY
SELECT JSON_VALUE(
    '{"name": "Alice"}'::json,
    '$.age'
    DEFAULT 0 ON EMPTY
);
-- 결과: 0

해결 방법

원인 1 해결: lax 모드 사용 또는 경로 존재 여부 사전 확인

strict 모드를 반드시 사용해야 하는 상황이 아니라면, lax 모드로 전환하는 것이 가장 간단한 해결책입니다. lax 모드는 경로가 없을 때 NULL을 반환하므로 애플리케이션 로직에서 NULL 처리를 통해 안전하게 사용할 수 있습니다.

-- 해결책 1: lax 모드로 전환
SELECT jsonb_path_value(
    '{"name": "Alice"}'::jsonb,
    'lax $.age'
);
-- 결과: NULL (에러 없음)

-- 해결책 2: jsonb_path_exists로 사전 확인 후 조회
SELECT
    CASE
        WHEN jsonb_path_exists(data, '$.age')
        THEN jsonb_path_value(data, '$.age')
        ELSE NULL
    END AS age
FROM (
    SELECT '{"name": "Alice"}'::jsonb AS data
) t;

-- 해결책 3: jsonb 연산자 사용 (간단한 키 조회 시)
SELECT ('{"name": "Alice"}'::jsonb)->>'age';
-- 결과: NULL (에러 없음)

원인 2 해결: 배열 크기 확인 후 접근

배열 인덱스 접근 전에 배열의 크기를 먼저 확인하거나, lax 모드를 활용하여 안전하게 처리합니다.

-- 해결책 1: jsonb_array_length로 크기 확인
DO $$
DECLARE
    v_data jsonb := '[1, 2, 3]'::jsonb;
    v_idx  int   := 10;
BEGIN
    IF jsonb_array_length(v_data) > v_idx THEN
        RAISE NOTICE 'Value: %', v_data->v_idx;
    ELSE
        RAISE NOTICE 'Index out of range';
    END IF;
END;
$$;

-- 해결책 2: lax 모드로 NULL 반환 활용
SELECT COALESCE(
    jsonb_path_value('[1,2,3]'::jsonb, 'lax $[10]'),
    '0'::jsonb
) AS safe_value;
-- 결과: 0

원인 3 해결: ON EMPTY 절 옵션 변경

ERROR ON EMPTY 대신 NULL ON EMPTY 또는 DEFAULT ... ON EMPTY를 사용하여 에러 없이 처리합니다.

-- 해결책 1: NULL ON EMPTY (기본값)
SELECT JSON_VALUE(
    '{"name": "Alice"}'::json,
    '$.age'
    NULL ON EMPTY
);
-- 결과: NULL

-- 해결책 2: DEFAULT 값 지정
SELECT JSON_VALUE(
    '{"name": "Alice"}'::json,
    '$.age'
    DEFAULT '-1' ON EMPTY
);
-- 결과: -1

-- 해결책 3: ON EMPTY와 ON ERROR 함께 처리
SELECT JSON_VALUE(
    '{"name": "Alice"}'::json,
    '$.age'
    DEFAULT 0 ON EMPTY
    DEFAULT -999 ON ERROR
);

예방 방법

1. JSON 스키마 검증 및 애플리케이션 레벨 유효성 검사 도입

JSON 데이터를 테이블에 저장하기 전에 CHECK 제약 조건이나 트리거를 활용하여 필수 필드가 반드시 존재하도록 강제하는 것이 중요합니다. 이를 통해 런타임에 경로가 없어서 발생하는 에러를 사전에 차단할 수 있습니다.

-- CHECK 제약 조건으로 필수 필드 보장
CREATE TABLE user_profiles (
    id   SERIAL PRIMARY KEY,
    data jsonb NOT NULL,
    CONSTRAINT chk_required_fields CHECK (
        jsonb_path_exists(data, '$.name')
        AND jsonb_path_exists(data, '$.email')
    )
);

-- 잘못된 데이터 삽입 시도 → 에러 발생
INSERT INTO user_profiles (data)
VALUES ('{"name": "Alice"}'::jsonb);
-- ERROR: new row for relation "user_profiles" violates check constraint

-- 올바른 데이터 삽입
INSERT INTO user_profiles (data)
VALUES ('{"name": "Alice", "email": "alice@example.com"}'::jsonb);

2. JSON Path 표현식 작성 시 lax 모드를 기본으로 사용하고 strict 모드는 목적이 명확할 때만 사용

일반적인 데이터 조회 쿼리에서는 lax 모드를 기본으로 사용하고, strict 모드나 ERROR ON EMPTY 옵션은 데이터 무결성 검증이 명확히 필요한 경우에만 제한적으로 사용하는 코딩 규칙을 팀 내에 정립해야 합니다. 또한 COALESCE나 NULLIF와 함께 사용하여 NULL 값을 적절히 처리하는 패턴을 표준화하면 유지보수성이 크게 향상됩니다.

-- 권장 패턴: lax 모드 + COALESCE로 기본값 처리
SELECT
    data->>'name'                                          AS name,
    COALESCE(jsonb_path_value(data, 'lax $.age'), '0')    AS age,
    COALESCE(data->>'email', 'unknown@example.com')       AS email
FROM user_profiles;

관련 에러

  • 22034 (invalid_sql_json_subscript): JSON 배열 인덱스가 유효하지 않은 타입(예: 문자열 인덱스)일 때 발생하는 에러로, 22035와 함께 JSON 배열 처리 시 자주 동반됩니다.
  • 22032 (invalid_json_text): 유효하지 않은 JSON 문자열을 파싱하려 할 때 발생하며, JSON 경로 조회 이전 단계에서 발생하는 에러입니다.
  • 22033 (invalid_sql_json_descriptor): JSON Path 표현식 자체가 문법적으로 잘못 작성되었을 때 발생하는 에러입니다.
  • 22036 (non_numeric_sql_json_item): JSON 경로가 반환한 아이템이 숫자가 아닌데 숫자 연산을 시도할 때 발생합니다.
  • 22037 (non_unique_keys_in_a_json_object): JSON 객체 내에 동일한 키가 중복으로 존재할 때 strict 모드에서 발생합니다.

이 에러들은 모두 SQLSTATE 22xxx 계열의 데이터 예외(Data Exception) 범주에 속하며, JSON 데이터 처리 파이프라인을 구성할 때 통합적으로 예외 처리 로직을 설계하는 것이 바람직합니다.


DBMS 에러 코드 시리즈

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

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

댓글 남기기