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

42704
2026년 07월 09일 | DBMS Error 가이드

이 글에서 다루는 내용

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

42704 undefined object 란?

PostgreSQL 에러 코드 42704는 undefined object로, 사용자가 참조하거나 삭제하거나 수정하려는 데이터베이스 객체(인덱스, 타입, 연산자, 캐스트, 텍스트 검색 구성요소 등)가 현재 데이터베이스에 존재하지 않을 때 발생합니다. 이 에러는 주로 DROP, ALTER, COMMENT ON 같은 DDL 구문에서 존재하지 않는 객체를 대상으로 작업할 때 나타납니다. 특히 마이그레이션 스크립트나 배포 자동화 환경에서 객체의 존재 여부를 확인하지 않고 실행할 경우 빈번하게 마주치는 에러입니다.


주요 발생 원인

  • 존재하지 않는 인덱스, 타입, 연산자 등에 대한 DROP 시도

가장 흔한 원인입니다. 개발자가 이미 삭제된 인덱스나 커스텀 타입을 다시 삭제하려 하거나, 오타로 인해 잘못된 객체 이름을 참조할 때 발생합니다. 예를 들어, CI/CD 파이프라인에서 같은 마이그레이션 스크립트가 두 번 실행되는 경우 두 번째 실행 시 이 에러가 발생합니다. 멱등성(idempotency)이 보장되지 않은 스크립트에서 특히 위험합니다.

  • 존재하지 않는 텍스트 검색 구성요소 참조 (Full-Text Search)

PostgreSQL의 Full-Text Search 기능에서 사용하는 TEXT SEARCH CONFIGURATION, TEXT SEARCH DICTIONARY, TEXT SEARCH PARSER, TEXT SEARCH TEMPLATE 등을 잘못된 이름으로 참조할 때 발생합니다. 한국어나 다국어 검색 환경을 구성하다 보면 커스텀 사전이나 구성(configuration)을 직접 정의하는 경우가 많은데, 이를 참조하는 시점에 아직 생성되어 있지 않다면 이 에러가 발생합니다.

  • 스키마 경로(search_path) 불일치로 인한 객체 미인식

search_path 설정이 올바르지 않으면 동일한 이름의 객체라도 PostgreSQL이 해당 스키마에서 찾지 못해 에러를 발생시킵니다. 여러 스키마를 운영하는 멀티테넌트 환경이나 public 스키마가 아닌 별도 스키마에 객체를 생성한 경우에 자주 발생합니다. 특히 배포 자동화 도구(Flyway, Liquibase 등)가 기본 search_path로 실행될 때 문제가 생기기 쉽습니다.


해결 방법

원인 1: 존재하지 않는 객체 DROP 시도

IF EXISTS 옵션을 활용하면 객체가 없어도 에러 없이 넘어갈 수 있습니다.

-- 에러 발생 예시: 존재하지 않는 인덱스 삭제 시도
DROP INDEX idx_users_email;
-- ERROR: 42704: index "idx_users_email" does not exist

-- 해결책: IF EXISTS 사용
DROP INDEX IF EXISTS idx_users_email;

-- 커스텀 타입 삭제 시에도 동일하게 적용
DROP TYPE IF EXISTS my_custom_status;

-- 연산자 클래스 삭제 예시
DROP OPERATOR CLASS IF EXISTS my_ops USING btree;

-- 존재 여부를 먼저 확인하는 방법 (pg_class 활용)
DO $$
BEGIN
    IF EXISTS (
        SELECT 1
        FROM pg_class c
        JOIN pg_namespace n ON n.oid = c.relnamespace
        WHERE c.relname = 'idx_users_email'
          AND c.relkind = 'i'
          AND n.nspname = 'public'
    ) THEN
        DROP INDEX public.idx_users_email;
        RAISE NOTICE 'Index dropped successfully.';
    ELSE
        RAISE NOTICE 'Index does not exist, skipping.';
    END IF;
END;
$$;

원인 2: 텍스트 검색 구성요소 참조 오류

현재 데이터베이스에 등록된 텍스트 검색 구성요소를 먼저 확인한 후 작업합니다.

-- 현재 등록된 TEXT SEARCH CONFIGURATION 목록 확인
SELECT cfgname, cfgnamespace::regnamespace AS schema
FROM pg_ts_config;

-- 현재 등록된 TEXT SEARCH DICTIONARY 목록 확인
SELECT dictname
FROM pg_ts_dict;

-- 에러 발생 예시: 존재하지 않는 설정 참조
ALTER TEXT SEARCH CONFIGURATION my_korean_config
    ALTER MAPPING FOR word WITH my_korean_dict;
-- ERROR: 42704: text search configuration "my_korean_config" does not exist

-- 해결책 1: 먼저 생성 후 참조
CREATE TEXT SEARCH CONFIGURATION my_korean_config (COPY = simple);

ALTER TEXT SEARCH CONFIGURATION my_korean_config
    ALTER MAPPING FOR word WITH my_korean_dict;

-- 해결책 2: IF EXISTS로 안전하게 삭제
DROP TEXT SEARCH CONFIGURATION IF EXISTS my_korean_config;
DROP TEXT SEARCH DICTIONARY IF EXISTS my_korean_dict;

원인 3: search_path 불일치 해결

-- 현재 search_path 확인
SHOW search_path;

-- 특정 세션의 search_path 변경
SET search_path TO myschema, public;

-- 특정 역할(Role)의 기본 search_path 설정
ALTER ROLE myapp_user SET search_path TO myschema, public;

-- 스키마를 명시적으로 지정하여 에러 방지
DROP INDEX IF EXISTS myschema.idx_users_email;

-- 객체가 어떤 스키마에 있는지 확인
SELECT n.nspname AS schema_name,
       c.relname AS object_name,
       c.relkind AS object_type
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'idx_users_email';

-- 연산자(Operator) 관련 42704 에러 확인 예시
SELECT oprname, oprnamespace::regnamespace
FROM pg_operator
WHERE oprname = '@@';

예방 방법

  • 모든 DDL 스크립트에 IF EXISTS / IF NOT EXISTS 패턴을 표준화하세요

마이그레이션 스크립트를 작성할 때 DROP 구문에는 항상 IF EXISTS를, CREATE 구문에는 항상 IF NOT EXISTS(또는 CREATE OR REPLACE)를 붙이는 것을 팀 컨벤션으로 정립하세요. 이렇게 하면 스크립트가 멱등성을 가지게 되어 동일한 스크립트를 여러 번 실행해도 에러 없이 동작합니다. CI/CD 파이프라인에서 마이그레이션 도구(Flyway, Liquibase)를 사용한다면 체크섬 검증과 함께 반드시 적용해야 할 Best Practice입니다.

“`sql

— 좋은 예: 멱등성이 보장된 스크립트

CREATE INDEX IF NOT EXISTS idx_orders_created_at

ON orders(created_at);

DROP INDEX IF EXISTS idx_orders_old_column;

CREATE OR REPLACE FUNCTION calculate_tax(amount NUMERIC)

RETURNS NUMERIC AS $$

BEGIN

RETURN amount * 0.1;

END;

$$ LANGUAGE plpgsql;

“`

  • 배포 전 pg_catalog 시스템 뷰로 객체 존재 여부를 사전 검증하세요

실제 배포 전에 대상 데이터베이스에서 스크립트가 참조하는 모든 객체의 존재 여부를 자동으로 검증하는 사전 검사(pre-flight check) 단계를 CI/CD 파이프라인에 추가하세요. pg_class, pg_type, pg_operator, pg_ts_config 등의 시스템 카탈로그를 활용하면 됩니다.

“`sql

— 배포 전 체크 스크립트 예시: 필요한 인덱스가 없으면 경고

DO $$

DECLARE

missing_objects TEXT := ”;

BEGIN

— 인덱스 존재 여부 확인

IF NOT EXISTS (

SELECT 1 FROM pg_class WHERE relname = ‘idx_users_email’ AND relkind = ‘i’

) THEN

missing_objects := missing_objects || ‘INDEX: idx_users_email’ || E’\n’;

END IF;

— 커스텀 타입 존재 여부 확인

IF NOT EXISTS (

SELECT 1 FROM pg_type WHERE typname = ‘my_custom_status’

) THEN

missing_objects := missing_objects || ‘TYPE: my_custom_status’ || E’\n’;

END IF;

IF missing_objects <> ” THEN

RAISE EXCEPTION ‘Pre-flight check failed. Missing objects: %’, missing_objects;

ELSE

RAISE NOTICE ‘Pre-flight check passed. All objects exist.’;

END IF;

END;

$$;

“`


관련 에러

  • 42883 undefined_function: 존재하지 않는 함수를 호출할 때 발생하는 에러로, 42704와 유사하게 객체 미존재 상황에서 발생합니다. 함수 이름이나 인자 타입이 다를 때 자주 마주칩니다.
  • 42P01 undefined_table: 존재하지 않는 테이블을 참조할 때 발생하며, 42704와 함께 DDL/DML 마이그레이션 스크립트에서 가장 많이 보이는 에러 중 하나입니다.
  • 42704와 42883의 차이: 42704는 인덱스, 타입, 연산자, 텍스트 검색 객체 등 비함수 객체에 대한 미정의 에러이고, 42883은 함수 및 프로시저에 특화된 미정의 에러입니다. 두 에러 모두 pg_catalog 시스템 뷰를 통해 객체 존재 여부를 사전에 확인함으로써 예방할 수 있습니다.
DBMS 에러 코드 시리즈

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

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

댓글 남기기