Fix “column … can only be updated to DEFAULT” in PostgreSQL

If you’re getting an error in PostgreSQL that tells you that a column “…can only be updated to DEFAULT” with detail that explains that it “…is an identity column defined as GENERATED ALWAYS“, it’s probably because you’re trying to update an identity column with your own value, but the identity column was created with the GENERATED ALWAYS option.

When an identity column was created with the GENERATED ALWAYS option, we can only use DEFAULT when updating that column.

So to fix this issue, either use DEFAULT as the new value, or alter the column to use the GENERATED AS DEFAULT option.

Another option is to insert a new row and use the OVERRIDING SYSTEM VALUE option in the insert statement.

Example of Error

Here’s an example of code that produces the error:

UPDATE Idiots 
SET IdiotId = 21
WHERE IdiotId = 20
RETURNING *;

Result:

ERROR:  column "idiotid" can only be updated to DEFAULT
DETAIL:  Column "idiotid" is an identity column defined as GENERATED ALWAYS.

I got that error because the IdiotId column was defined as GENERATED ALWAYS when it was created. When this option is selected, the only value we can use to update the column is DEFAULT.

Solution 1

One solution to this issue is to set the column to DEFAULT:

UPDATE Idiots 
SET IdiotId = DEFAULT
WHERE IdiotId = 20
RETURNING *;

Result:

 idiotid | idiotname 
---------+-----------
       4 | Homer

This time we didn’t get an error. The system generated its own value for the identity column.

Solution 2

Another solution is to alter the column so that it’s defined using the GENERATED BY DEFAULT option:

ALTER TABLE Idiots
ALTER COLUMN IdiotId SET GENERATED BY DEFAULT;

Now we can insert our preferred value into the identity column:

UPDATE Idiots 
SET IdiotId = 21
WHERE IdiotId = 20
RETURNING *;

Result:

 idiotid | idiotname 
---------+-----------
      21 | Homer

This time we didn’t get an error.

Solution 3

When a column has been created with the GENERATED ALWAYS option, we have more flexibility when inserting data (as opposed to updating existing data). In particular, when using the INSERT statement, PostgreSQL provides us with the OVERRIDING SYSTEM VALUE option.

Therefore, another option available to us is to insert a new value altogether using the OVERRIDING SYSTEM VALUE in the INSERT statement. This might be an option if you’re unable to alter the table like we did in the previous example.

First, let’s alter the identity column back to use our original GENERATED ALWAYS:

ALTER TABLE Idiots
ALTER COLUMN IdiotId SET GENERATED ALWAYS;

Now let’s insert a new value using OVERRIDING SYSTEM VALUE:

INSERT INTO Idiots ( IdiotId, IdiotName ) 
OVERRIDING SYSTEM VALUE
VALUES ( 20, 'Homer' )
RETURNING *;

Result:

 idiotid | idiotname 
---------+-----------
      20 | Homer

This time my custom value was accepted. In other words, I overrode the value that the identity column was going to generate and I inserted my own.