Press ESC to close

Skip to main content
< All Topics
Print

Does PostgreSQL Return an SQL Code for Duplicate Key in Golang?

When building backend applications using PostgreSQL with Golang, handling duplicate key errors correctly is essential for maintaining data integrity and delivering predictable API behavior. This knowledge base article explains whether PostgreSQL returns an SQL error code for duplicate key violations and how to properly handle it in Go applications.

Quick Answer

Yes. PostgreSQL returns a specific SQLSTATE error code for duplicate key violations.

SQLSTATE Code: 23505

This error represents a unique_violation, triggered when a UNIQUE constraint or PRIMARY KEY constraint is violated.

What Triggers a Duplicate Key Error in PostgreSQL?

PostgreSQL raises error 23505 when:

  • A PRIMARY KEY constraint is violated
  • A UNIQUE constraint is violated
  • A UNIQUE INDEX is violated

Example

INSERT INTO users (email)
VALUES ('[email protected]');

If email has a UNIQUE constraint and the value already exists, PostgreSQL returns:

ERROR: duplicate key value violates unique constraint "users_email_key"
SQLSTATE: 23505

Understanding SQLSTATE Code 23505

PostgreSQL follows the SQL standard for error codes.

  • The class 23 represents Integrity Constraint Violations.
  • The specific code 23505 represents Unique Violation.

Using SQLSTATE codes is recommended because they are stable and standardized, unlike error message strings that may vary.


Handling Duplicate Key Errors in Golang

In Go applications, PostgreSQL errors can be accessed via driver-specific error types.

Using lib/pq

import (
    "database/sql"
    "github.com/lib/pq"
)

_, err := db.Exec("INSERT INTO users(email) VALUES($1)", email)
if err != nil {
    if pqErr, ok := err.(*pq.Error); ok {
        if pqErr.Code == "23505" {
            fmt.Println("Duplicate key detected")
        }
    }
}

Using pgx

import (
    "github.com/jackc/pgconn"
)

_, err := conn.Exec(ctx, "INSERT INTO users(email) VALUES($1)", email)
if err != nil {
    if pgErr, ok := err.(*pgconn.PgError); ok {
        if pgErr.Code == "23505" {
            fmt.Println("Duplicate key detected")
        }
    }
}

Instead:

Production Best Practices

Avoid checking for duplicate key errors using string matching such as:

if strings.Contains(err.Error(), "duplicate key")
  • Check the SQLSTATE code (23505)
  • Map it to a domain-specific error
  • Return an appropriate HTTP status code (e.g., 409 Conflict in REST APIs)

Example

return errors.New("email already exists")

Preventing Duplicate Key Errors Using UPSERT

PostgreSQL supports ON CONFLICT, which allows safe handling of duplicate keys.

Option 1: Do Nothing

INSERT INTO users(email)
VALUES ('[email protected]')
ON CONFLICT (email)
DO NOTHING;

Option 2: Update Existing Record

INSERT INTO users(email)
VALUES ('[email protected]')
ON CONFLICT (email)
DO UPDATE SET updated_at = NOW();

Related PostgreSQL Error Codes

SQLSTATE CodeDescription
23505Unique violation
23503Foreign key violation
23502Not null violation
22001String data too long
42601SQL syntax error

Frequently Asked Questions

Does PostgreSQL always return 23505 for duplicate key violations?

Yes. For UNIQUE and PRIMARY KEY constraint violations, PostgreSQL consistently returns SQLSTATE 23505.

Should I rely on error messages instead of SQLSTATE codes?

No. Error messages may vary. SQLSTATE codes are standardized and should be used for reliable error handling.

Does this work with both lib/pq and pgx?

Yes. Both drivers expose the SQLSTATE code through their respective error structures.


Final Thoughts

PostgreSQL returns SQLSTATE error code 23505 for duplicate key violations. In Golang, this can be reliably detected using driver-specific error types such as pq.Error or pgconn.PgError.

Proper handling ensures:

  • Clean and predictable API responses
  • Improved user experience
  • Strong data integrity
  • Production-grade reliability

This approach is recommended for all Go applications interacting with PostgreSQL in production environments.

Table of Contents