error postgresql

PostgreSQL Error 23505 - Unique Violation

Understanding PostgreSQL error 23505 unique_violation - a duplicate value violates a unique constraint on the table.

What It Means

PostgreSQL error code 23505 (unique_violation) occurs when an INSERT or UPDATE statement attempts to store a value that would violate a unique constraint or unique index. This means a row with the same value(s) already exists in the column(s) covered by the constraint.

Common Causes

  • Inserting a duplicate primary key value
  • Inserting a duplicate value in a column with a UNIQUE constraint
  • Concurrent inserts creating race conditions
  • Application retrying an insert that already succeeded
  • Bulk data imports with duplicate rows
  • Sequence/serial counter out of sync after manual data insertion

How to Fix

Use ON CONFLICT (upsert)

-- Insert or update on conflict
INSERT INTO users (email, name)
VALUES ('john@example.com', 'John Doe')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name, updated_at = NOW();

-- Insert or do nothing on conflict
INSERT INTO users (email, name)
VALUES ('john@example.com', 'John Doe')
ON CONFLICT (email) DO NOTHING;

-- With composite unique constraint
INSERT INTO user_roles (user_id, role_id)
VALUES (1, 2)
ON CONFLICT (user_id, role_id) DO NOTHING;

Handle in application code

// Node.js with pg
const { Pool } = require('pg');
const pool = new Pool();

async function createUser(email, name) {
  try {
    const result = await pool.query(
      'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *',
      [email, name]
    );
    return result.rows[0];
  } catch (error) {
    if (error.code === '23505') {
      throw new Error(`User with email ${email} already exists`);
    }
    throw error;
  }
}
# Python with psycopg2
import psycopg2

try:
    cursor.execute(
        "INSERT INTO users (email, name) VALUES (%s, %s)",
        (email, name)
    )
    conn.commit()
except psycopg2.errors.UniqueViolation:
    conn.rollback()
    print(f"User with email {email} already exists")

Fix sequence out of sync

-- If serial/sequence is behind the actual data (common after imports)
SELECT MAX(id) FROM users;  -- Check the highest ID

-- Reset the sequence
SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));

-- Or set to a specific value
SELECT setval('users_id_seq', 1000, true);

Find duplicates

-- Find duplicate values in a column
SELECT email, COUNT(*)
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

-- Find which constraint was violated (from error message)
SELECT conname, contype, pg_get_constraintdef(oid)
FROM pg_constraint
WHERE conrelid = 'users'::regclass;
  • PostgreSQL 23503 - Foreign key violation: Referencing a non-existent parent row.
  • PostgreSQL 42P01 - Undefined table: The table itself doesn’t exist.
  • MySQL 1062 - Duplicate entry: The MySQL equivalent of this error.