How to Fix PostgreSQL Error: Null Value Violates Not-Null Constraint

The "Null value violates not-null constraint" error occurs when attempting to insert or update a row with a NULL value in a column that has a NOT NULL constraint. This constraint ensures that every row must have a value for that column, preventing incomplete or missing data.

Impact

This error prevents INSERT and UPDATE operations from completing, causing application failures when required data is missing. It's common when form validation is insufficient, during data migrations, or when APIs receive incomplete data.

Common Causes

  1. Missing required field in INSERT statement
  2. Explicitly setting column to NULL
  3. Application not validating required fields
  4. Default value not specified for new columns
  5. Data migration with incomplete source data
  6. Column made NOT NULL without handling existing NULLs
  7. Trigger or function setting value to NULL

Troubleshooting and Resolution Steps

  1. Identify the column and provide a value:

    -- Error: null value in column "email" of relation "users" violates not-null constraint
    
    -- WRONG: Missing required column
    INSERT INTO users (name) VALUES ('John Doe');
    
    -- CORRECT: Include all required columns
    INSERT INTO users (name, email)
    VALUES ('John Doe', 'john@example.com');
    
  2. Check table constraints:

    -- View table structure and constraints
    \d users
    
    -- Query constraints
    SELECT column_name, is_nullable, column_default
    FROM information_schema.columns
    WHERE table_name = 'users' AND is_nullable = 'NO';
    
  3. Use default values:

    -- Set default value for column
    ALTER TABLE users ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP;
    ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';
    ALTER TABLE users ALTER COLUMN count SET DEFAULT 0;
    
    -- Now INSERT can omit these columns
    INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
    -- created_at, status, and count will use defaults
    
  4. Add column with default for existing rows:

    -- Add NOT NULL column with default value
    ALTER TABLE users ADD COLUMN phone VARCHAR(20) DEFAULT '';
    
    -- Add NOT NULL column in two steps
    ALTER TABLE users ADD COLUMN phone VARCHAR(20);
    UPDATE users SET phone = '' WHERE phone IS NULL;
    ALTER TABLE users ALTER COLUMN phone SET NOT NULL;
    
  5. Make column nullable if appropriate:

    -- Remove NOT NULL constraint
    ALTER TABLE users ALTER COLUMN middle_name DROP NOT NULL;
    
    -- Now NULL values are allowed
    INSERT INTO users (name, email, middle_name)
    VALUES ('John Doe', 'john@example.com', NULL);
    
  6. Handle existing NULL values before adding NOT NULL:

    -- Check for existing NULLs
    SELECT COUNT(*) FROM users WHERE email IS NULL;
    
    -- Update NULL values
    UPDATE users SET email = 'unknown@example.com' WHERE email IS NULL;
    
    -- Now add NOT NULL constraint
    ALTER TABLE users ALTER COLUMN email SET NOT NULL;
    
  7. Use COALESCE for conditional defaults:

    -- Provide fallback value if NULL
    INSERT INTO users (name, email, phone)
    VALUES ('John', 'john@example.com', COALESCE(NULL, 'N/A'));
    
    -- In UPDATE
    UPDATE users
    SET phone = COALESCE(new_phone, current_phone, 'N/A')
    WHERE id = 123;
    
  8. Handle NULL in application before INSERT:

    # Python example with psycopg2
    def create_user(name, email, phone=None):
        # Ensure required fields have values
        if not email:
            raise ValueError("Email is required")
    
        # Provide default for optional fields that are NOT NULL
        phone = phone or ''
    
        cursor.execute(
            "INSERT INTO users (name, email, phone) VALUES (%s, %s, %s)",
            (name, email, phone)
        )
    
  9. Use generated columns for computed values:

    -- Create generated column (PostgreSQL 12+)
    ALTER TABLE users ADD COLUMN full_name TEXT
    GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED;
    
    -- generated columns are automatically populated
    
  10. Transaction-safe migration:

    -- Safe migration with NOT NULL
    BEGIN;
    
    -- Add column as nullable
    ALTER TABLE users ADD COLUMN new_column VARCHAR(100);
    
    -- Populate with values
    UPDATE users SET new_column = 'default_value';
    
    -- Make it NOT NULL
    ALTER TABLE users ALTER COLUMN new_column SET NOT NULL;
    
    COMMIT;
    

Additional Information

  • NOT NULL constraints are checked immediately on INSERT/UPDATE
  • Default values are applied before constraint checking
  • Generated columns automatically populate values
  • Check constraints can provide more complex validation
  • Use application-level validation as first line of defense
  • Consider using empty strings vs NULL based on business logic
  • Document which fields are required in API/schema documentation

Frequently Asked Questions

Q: What's the difference between NULL and an empty string?
A: NULL means "no value" or "unknown", while an empty string ('') is a value that happens to be blank. NOT NULL constraints prevent NULL but allow empty strings.

Q: Can a column have both NOT NULL and a default value?
A: Yes, this is common. The default ensures INSERT without that column still works, while NOT NULL prevents explicit NULL insertions.

Q: How do I make a primary key column?
A: Primary keys automatically include NOT NULL: ALTER TABLE users ADD PRIMARY KEY (id); or during creation: id SERIAL PRIMARY KEY.

Q: Can I add NOT NULL to a column with existing NULL values?
A: No, you must first UPDATE all NULL values to non-NULL, then add the constraint.

Q: What happens if I omit a NOT NULL column without a default?
A: You'll get this error. You must either provide a value, add a default, or remove the NOT NULL constraint.

Q: How do I check if a column is NOT NULL programmatically?
A: Query information_schema:

SELECT is_nullable
FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'email';

Q: Should I use NOT NULL for every column?
A: No, use it only for truly required fields. Optional fields should allow NULL unless there's a business reason for a default value.

Pulse - Elasticsearch Operations Done Right

Pulse can solve your Elasticsearch issues

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.