ERROR: integer out of range (SQLSTATE 22003) means a value or a calculation went past 2,147,483,647, the largest value of PostgreSQL's integer. Change the column to bigint, or cast one side of the calculation to bigint.

In the test the column views integer held 2147483647, and both an insert of 2147483648 and views + 1 failed. After ALTER TABLE page_view ALTER COLUMN views TYPE bigint both worked. A multiplication of two integer literals failed the same way until one side was cast.

The error

INSERT INTO page_view (page, views) VALUES ('/home', 2147483647);
INSERT 0 1
INSERT INTO page_view (page, views) VALUES ('/blog', 2147483648);
psql:/tmp/f22003.sql:4: ERROR:  22003: integer out of range
LOCATION:  int84, int8.c:1254
UPDATE page_view SET views = views + 1 WHERE page = '/home';
psql:/tmp/f22003.sql:5: ERROR:  22003: integer out of range
LOCATION:  int4pl, int.c:827
SELECT 50000 * 50000 AS product;
psql:/tmp/f22003.sql:6: ERROR:  22003: integer out of range
LOCATION:  int4mul, int.c:855

Why it happens

In the integer column 2147483647 was stored and 2147483648 was not. The three failures in the test are three ways to reach the limit. The insert sent a number too large for the column. The update added 1 to a value already at the top. The SELECT never touched a table: 50000 * 50000 is 2,500,000,000, and with both literals typed as integer the product was computed as an integer and overflowed. The message does not name the column, so look at the statement on the line psql reports.

The update case is the one that surprises: views + 1 is harmless SQL, and it failed here because the stored value sat at 2147483647, the top of the range.

The fix

SELECT 50000::bigint * 50000 AS product;
  product
------------
 2500000000
(1 row)

ALTER TABLE page_view ALTER COLUMN views TYPE bigint;
ALTER TABLE
UPDATE page_view SET views = views + 1 WHERE page = '/home';
UPDATE 1
INSERT INTO page_view (page, views) VALUES ('/blog', 2147483648);
INSERT 0 1
SELECT page, views FROM page_view ORDER BY id;
 page  |   views
-------+------------
 /home | 2147483648
 /blog | 2147483648
(2 rows)

Casting one operand with ::bigint made the multiplication a bigint multiplication, and the result came back. For a column, ALTER COLUMN ... TYPE bigint widened it and the update and insert that had failed then went through. The test table had one row at that point; time the change on a large table before running it in production. In application code, map the widened column to a 64-bit type such as C# long.

How it was reproduced

A postgres:18 container (PostgreSQL 18.4, Debian 18.4-1.pgdg13+1) on Docker Engine 29.9.2, database lab, table page_view (id serial, page text, views integer). The script f22003.sql ran with docker exec fix8-pg3 sh -c "psql -U postgres -d lab -e -f /tmp/f22003.sql 2>&1" and \set VERBOSITY verbose at its top for the SQLSTATE. The container name is the test's own.

Frequently asked

What is the maximum value of an integer column in PostgreSQL?
2147483647 was stored in the test and 2147483648 failed with 22003 integer out of range. A bigint column took 2147483648.
How do I fix integer out of range in a PostgreSQL calculation?
Cast one operand to bigint. SELECT 50000 * 50000 failed with 22003 in the test and SELECT 50000::bigint * 50000 returned 2500000000.
How do I change a PostgreSQL column from integer to bigint?
Run ALTER TABLE page_view ALTER COLUMN views TYPE bigint. In the test the update and insert that had failed with integer out of range worked right after it.

More decoded errors in the Fixes category.