PostgreSQL "invalid input syntax for type integer": find the bad value and handle it
Fix "invalid input syntax for type integer": find empty strings and text where a number is expected, convert with NULLIF and pg_input_is_valid, import clean data.
by OhSudo ·
Checked on real software: PostgreSQL 18.6 · November 2026How we check
Part of a learning path:SQL and PostgreSQL, step by step
A query or an import fails on a value PostgreSQL can’t read as a number:
ERROR: invalid input syntax for type integer: "abc"The column is an integer, and the value you gave can’t be turned into one. The value in the quotes is the culprit — and very often it’s empty: invalid input syntax for type integer: "". PostgreSQL is strict here on purpose: it would rather stop than guess that '' means 0, or that '12a' means 12.
So the questions are: where does the bad value come from, and what should it mean? Every query below runs in the SQL Playground on the sample shop database.
TL;DR
1. The usual sources
An empty form field or query parameter. The app sends '' when a user leaves a field blank, and the query compares it to a number column:
Fix it in the app — send NULL (or skip the condition) for an empty field, and validate input before it reaches SQL.
A text column cast to a number. Data stored as text (imported, or from a “flexible” schema) mostly holds numbers — and one row doesn’t:
CREATE TABLE import_raw (sku text, qty text);INSERT INTO import_raw VALUES ('NET-100', '5'), ('NET-200', ''), ('NET-300', '12 pcs'), ('NET-400', '7');Parameters glued into the SQL text. Building queries by concatenating strings ("… WHERE id = '" + id + "'") turns every bad input into an SQL error — and into an SQL injection risk. Use bound parameters, and the driver sends a proper NULL or number.
2. Find the bad rows
Since PostgreSQL 16, pg_input_is_valid tells you whether a value would convert, without failing:
On older versions, a regular expression does the same for plain integers:
3. Convert safely
Decide what the bad values mean, then say it in SQL:
-- Empty means "unknown": NULLSELECT sku, NULLIF(trim(qty), '')::integer AS qtyFROM import_rawWHERE pg_input_is_valid(NULLIF(trim(qty), ''), 'integer') OR NULLIF(trim(qty), '') IS NULL;-- Anything that isn't a number becomes NULL, and stays visible for a later fixSELECT sku, CASE WHEN pg_input_is_valid(qty, 'integer') THEN qty::integer END AS qty, qty AS originalFROM import_raw;You can try a pattern on your own values in the Regex Tester first. Avoid “cleaning” with regexp_replace(qty, '\D', '', 'g'): it turns '12 pcs' into 12, but also '1-2' into 12 and 'v2.0' into 20.
4. Imports: load as text first
When a CSV import fails with this error, the line number is in the message (CONTEXT: COPY products, line 1042, column stock: ""). Two reliable patterns:
- Empty strings as NULL. With
COPY … (FORMAT csv), an empty unquoted field is already NULL; a quoted empty string ("") is not.FORCE_NULL (stock)treats both as NULL. - A staging table. Load everything into
textcolumns, check and convert with the queries above, thenINSERT … SELECTinto the real table. Bad rows can be reported instead of stopping the whole import.
Also check the obvious: a header line not skipped (HEADER true), columns in a different order than the table, a different delimiter.
Shell, we have a problem!
Similar, but different: operator does not exist: integer = text — the value is typed as text (often a bound parameter of the wrong type), and PostgreSQL won’t compare it to a number without a cast. value "3000000000" is out of range for type integer — a valid number, too big for integer; use bigint. invalid input syntax for type uuid / date / numeric — the same problem for other types, with the same fixes (pg_input_is_valid(x, 'date')). value too long for type character varying is text longer than the column allows.
SELECT * FROM practice;
Practice this in the SQL Playground
Open a real PostgreSQL 18.6 database in your browser with this article’s sample data loaded.
Found this useful? Share it.
Found a mistake? Let us know at contact@ohsudo.com.