42P07ERRORTier 1 — Safe✅ HIGH confidencerelation already exists
What this means
A CREATE TABLE, CREATE VIEW, CREATE MATERIALIZED VIEW, CREATE INDEX, or CREATE SEQUENCE statement attempted to create a relation with a name that already exists in the current schema.
Why it happens
- 1Running CREATE TABLE without IF NOT EXISTS in a migration that has already been applied
- 2A table with the same name exists in the schema the statement resolves to
- 3CREATE INDEX with a name that is already used by another index on any table in the schema
How to reproduce
CREATE TABLE is executed twice for the same table name.
CREATE TABLE events (id SERIAL PRIMARY KEY, name TEXT);
CREATE TABLE events (id SERIAL PRIMARY KEY, name TEXT); -- triggers 42P07Fix 1: Use IF NOT EXISTS
In idempotent migration scripts.
CREATE TABLE IF NOT EXISTS events (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_events_name ON events (name);Why this works
IF NOT EXISTS checks pg_class for a relation with the given name in the target schema. If found, the statement is suppressed with a NOTICE. The check and the creation are not atomic (a race is possible in concurrent DDL), but this is acceptable for migrations run under a migration lock.
What not to do
Use DROP TABLE IF EXISTS before CREATE TABLE in migrations
Why it's wrong: Drops all data and dependent objects silently; idempotent CREATE with IF NOT EXISTS is always safer.
Sources
📚 Official docs: https://www.postgresql.org/docs/current/errcodes-appendix.html
📚 Feature docs: https://www.postgresql.org/docs/current/sql-createtable.html
Confidence assessment
✅ HIGH confidence
Well-documented and stable. IF NOT EXISTS for CREATE TABLE was added in Postgres 9.1. Edge case: index names are global within a schema, not scoped to a table; two tables cannot share an index name.
See also
🔗 Related errors
📄 Reference pages