PostgreSQL Error 42704: undefined object
PostgreSQL error code 42704 (undefined_object) is raised when you reference a database object — such as an index, data type, operator, cast, or text search component — that does not exist in the current database. This commonly occurs in DROP, ALTER, or COMMENT ON DDL statements targeting a non-existent object. It is especially prevalent in migration scripts or automated deployment pipelines that lack proper existence checks.
Top 3 Causes
1. Dropping a Non-Existent Index or Type
The most frequent cause. A script tries to drop an index or custom type that has already been removed, or a typo causes the wrong object name to be referenced.
-- Triggers ERROR 42704
DROP INDEX idx_users_email;
-- ERROR: index "idx_users_email" does not exist
-- Fix: use IF EXISTS
DROP INDEX IF EXISTS idx_users_email;
-- Same pattern for custom types
DROP TYPE IF EXISTS my_custom_status;
-- And operator classes
DROP OPERATOR CLASS IF EXISTS my_ops USING btree;
2. Referencing a Non-Existent Text Search Component
PostgreSQL Full-Text Search uses objects like TEXT SEARCH CONFIGURATION and TEXT SEARCH DICTIONARY. If these are referenced before they are created, error 42704 is raised.
-- Check existing text search configurations first
SELECT cfgname FROM pg_ts_config;
-- Triggers ERROR 42704
ALTER TEXT SEARCH CONFIGURATION my_custom_config
ALTER MAPPING FOR word WITH my_custom_dict;
-- ERROR: text search configuration "my_custom_config" does not exist
-- Fix: create it first, then alter
CREATE TEXT SEARCH CONFIGURATION my_custom_config (COPY = simple);
ALTER TEXT SEARCH CONFIGURATION my_custom_config
ALTER MAPPING FOR word WITH my_custom_dict;
-- Safe cleanup
DROP TEXT SEARCH CONFIGURATION IF EXISTS my_custom_config;
3. Schema search_path Mismatch
When search_path is not configured correctly, PostgreSQL cannot locate an object even if it exists under a different schema.
-- Check current search_path
SHOW search_path;
-- Fix for the session
SET search_path TO myschema, public;
-- Fix permanently for a role
ALTER ROLE myapp_user SET search_path TO myschema, public;
-- Always use schema-qualified names to be safe
DROP INDEX IF EXISTS myschema.idx_users_email;
-- Find which schema an object lives in
SELECT n.nspname AS schema, c.relname AS object
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'idx_users_email';
Quick Fix Solutions
- Always append
IF EXISTStoDROPstatements andIF NOT EXISTStoCREATEstatements to make scripts idempotent. - Use schema-qualified object names (
schema.object_name) to avoidsearch_pathambiguity. - Query
pg_catalogsystem views (pg_class,pg_type,pg_operator,pg_ts_config) to verify object existence before executing DDL.
-- Idempotent migration script pattern
CREATE INDEX IF NOT EXISTS idx_orders_created_at ON orders(created_at);
DROP INDEX IF EXISTS idx_orders_old;
-- Pre-flight existence check
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_class
WHERE relname = 'idx_users_email' AND relkind = 'i'
) THEN
RAISE EXCEPTION 'Required index idx_users_email is missing!';
END IF;
END;
$$;
Prevention Tips
Standardize
IF EXISTS/IF NOT EXISTSacross all DDL scripts. Make it a team convention so every migration is idempotent and safe to re-run in CI/CD pipelines.Add a pre-flight check step before deployments. Query system catalogs to validate all required objects exist before running migration scripts, catching issues before they hit production.
Related Errors
-
42883
undefined_function— Same class of error but specific to functions and procedures. -
42P01
undefined_table— Raised when a referenced table does not exist; frequently seen alongside 42704 in migration scripts.
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)