), commas in numbers, or text null representations like `\"na\"` or `\"NULL\"`.\n\n**`ERROR: invalid input syntax for type numeric: \"$1.00\"` (SQL state: 22P02)** — Currency-formatted values with ` PostgreSQL COPY Error: Fix Invalid Input Syntax in CSV Import - SplitForge Blog , `€`, or commas cannot be parsed as NUMERIC. Strip formatting before import.\n\n**`ERROR: invalid input syntax for type date: \"12/09/2011\"` (SQL state: 22007)** — Date format mismatch. PostgreSQL expects `YYYY-MM-DD` by default. US-format dates (`MM/DD/YYYY`) require explicit `DATEFORMAT` specification or pre-conversion.\n\n**`ERROR: missing data for column \"colname\"` (CONTEXT: COPY table, line N)** — The row at line N has fewer comma-separated values than the table has columns. Check for truncated rows, mismatched delimiters, or unmatched quotes causing multiple rows to merge.\n\n**`ERROR: extra data after last expected column`** — The row has more values than the table has columns. Check for embedded commas in unquoted fields.\n\n**`ERROR: invalid input syntax for integer: \"3192\"` (BOM character)** — The invisible `` (U+FEFF) character at the start of the file is being read as part of the first field's value. The file has a UTF-8 BOM that must be stripped.\n\n**`ERROR: value too long for type character varying(N)`** — A text value exceeds the column's defined character limit. Run `SELECT MAX(LENGTH(column_name)) FROM table_name` to identify the longest values.\n\n**`ERROR: null value in column \"colname\" of relation \"table\" violates not-null constraint`** — Empty CSV cells are being interpreted as NULL, but the column has a NOT NULL constraint. You must handle empty values explicitly.\n\n---\n\n## Fast Fix (2 Minutes)\n\n**If your PostgreSQL COPY command just failed, try this first:**\n\n1. **Read the CONTEXT line** — PostgreSQL tells you the exact line number. Count to that line in your CSV and inspect the value.\n2. **Check for BOM** — If the error is on line 1 and shows a garbled character before your first value, open the file in Notepad++ → Encoding → check if it shows \"UTF-8-BOM\". Remove it.\n3. **Check column count** — Run `SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'yourtable'` and verify it matches your CSV column count.\n4. **Test with 5 rows** — Create a 5-row test CSV with your cleanest data. If that imports, the problem is in a specific row of your full file.\n5. **Add NULL AS option** — If you have empty cells: `COPY table FROM 'file.csv' WITH (FORMAT CSV, HEADER, NULL '')` treats empty strings as NULL.\n\n**If the error persists on specific rows, continue below.**\n\n---\n\n**TL;DR:** PostgreSQL COPY is all-or-nothing — one bad row fails the entire import. The most common causes are data type mismatches (text in numeric columns, wrong date formats), BOM characters making line 1 fail, and column count errors from unquoted fields with embedded commas. Validate your CSV with [SplitForge Data Validator](/tools/data-validator) to find all errors before running COPY.\n\n---\n\nYou're migrating 2 million rows of transaction data into PostgreSQL. You run the COPY command. Six seconds later: `ERROR: invalid input syntax for type numeric: \"na\" CONTEXT: COPY transactions, line 847, column amount: \"na\"`. The import rolls back entirely. You're at zero rows imported.\n\nPostgreSQL COPY is transactional. One bad row cancels every row. This is by design — partial imports create data integrity problems worse than failed ones. The solution is fixing the CSV before running COPY, not finding workarounds after.\n\nEach error was reproduced using PostgreSQL 16 COPY command via psql, March 2026.\n\n---\n\n| Error / Symptom | Root Cause | Fix |\n|---|---|---|\n| `invalid input syntax for type integer: \"value\"` | Text/null in integer column | Strip currency, use NULL AS, check header inclusion |\n| `invalid input syntax for type numeric: \"$1.00\"` | Currency formatting in numeric column | Remove $, €, commas from numeric fields |\n| `invalid input syntax for type date: \"MM/DD/YYYY\"` | Wrong date format for PostgreSQL | Convert to YYYY-MM-DD or use DATEFORMAT |\n| `missing data for column \"colname\"` | Fewer values than columns in that row | Check for unmatched quotes causing row merges |\n| `extra data after last expected column` | More values than columns in that row | Quote fields containing commas |\n| `invalid input syntax for integer: \"3192\"` | UTF-8 BOM on first byte of file | Strip BOM before COPY |\n| `value too long for type character varying(N)` | Cell value exceeds column char limit | Check MAX(LENGTH()) and expand column or truncate |\n| `null value violates not-null constraint` | Empty cells where NOT NULL expected | Replace empty cells with default values |\n| `unterminated CSV quoted field` | Opening quote with no closing quote | Find unmatched quotes in CSV — common in Excel exports with commas in values |\n| `unexpected end of data` | Last row has fewer columns than expected | Check for truncated file or missing trailing delimiter |\n| `invalid byte sequence for encoding \"UTF8\"` | File contains non-UTF8 bytes | Re-encode file to UTF-8 before import |\n| `could not open file for reading: Permission denied` | PostgreSQL server can't read the file path | Use \\copy (client-side) or fix server file permissions |\n| `could not open file for reading: No such file or directory` | Wrong path or using COPY instead of \\copy | Switch to \\copy or verify the server-side path |\n| `ERROR: deadlock detected` | Concurrent import processes competing | Run single-threaded; use \\copy instead of parallel COPY |\n| `invalid input syntax for type boolean: \"yes\"` | PostgreSQL expects `true`/`false`, not `yes`/`no` | Replace `yes`/`no` with `true`/`false` in CSV |\n\n---\n\n## COPY Format Options Quick Reference\n\n| Option | Syntax | When to use |\n|---|---|---|\n| `FORMAT` | `FORMAT CSV` | Always — specifies CSV parsing mode |\n| `HEADER` | `HEADER` or `HEADER true` | When first row is column headers |\n| `DELIMITER` | `DELIMITER ','` | Non-comma delimiters (tab: `DELIMITER E'\\t'`) |\n| `NULL` | `NULL 'na'` | When null values appear as strings (`na`, `N/A`, `NULL`) |\n| `ENCODING` | `ENCODING 'WIN1252'` | Windows-exported files with non-UTF8 encoding |\n| `QUOTE` | `QUOTE '\"'` | Non-standard quote character (default is double-quote) |\n| `ESCAPE` | `ESCAPE '\\'` | Non-standard escape character |\n| `FREEZE` | `FREEZE` | Bulk-load optimization (requires empty table, superuser) |\n\n**Full example with common options:**\n```sql\nCOPY my_table FROM '/path/file.csv'\nWITH (FORMAT CSV, HEADER, NULL '', ENCODING 'UTF8', DELIMITER ',');\n```\n\n---\n\n## How PostgreSQL COPY Compares to Other Import Systems\n\n| Platform | Strict on data types? | Updates existing rows? | Deduplicates? | Safe date format | Max rows |\n|---|---|---|---|---|---|\n| **PostgreSQL COPY** | Yes — errors immediately, full rollback | N/A (append only) | No | YYYY-MM-DD | Server/memory limits |\n| monday.com | Yes on labels/status — silent drop | No — append only | No | YYYY-MM-DD | 8,000 |\n| Google Sheets | No — silent coercion/loss | Yes (paste over) | No | YYYY-MM-DD safest | 10M cells |\n| Notion | Partial — silent drop | No — append only | No | YYYY-MM-DD safest | ~50K practical |\n| NetSuite | Yes on references — row-level error | Yes (Update mode) | No | Account date format | Import Assistant limits |\n\nPostgreSQL COPY is the strictest of all: one bad row in 2 million rows fails everything. The tradeoff is complete data integrity — there is no partial import.\n\n---\n\n## Table of Contents\n\n- [COPY vs \\\\copy: The Path Problem](#copy-vs-copy-the-path-problem)\n- [Fix 1: Data Type Mismatches](#fix-1-data-type-mismatches)\n- [Fix 2: Date Format Errors](#fix-2-date-format-errors)\n- [Fix 3: Column Count Errors](#fix-3-column-count-errors)\n- [Fix 4: BOM Character on Line 1](#fix-4-bom-character-on-line-1)\n- [Fix 5: NULL and Empty Value Handling](#fix-5-null-and-empty-value-handling)\n- [Fix 6: Encoding Mismatch](#fix-6-encoding-mismatch)\n- [Pre-Import Validation Workflow](#pre-import-validation-workflow)\n- [Additional Resources](#additional-resources)\n- [FAQ](#faq)\n\n---\n\n**This guide is for:** Database administrators, backend developers, and data engineers importing CSV data into PostgreSQL using the COPY command or pgAdmin's import feature. Basic SQL knowledge is assumed.\n\n---\n\n\u003c!-- DIFFERENTIATION CLAIM: precision — COPY vs \\copy server/client path distinction is the #1 missed root cause for permission and file-not-found errors; most guides don't explain it clearly -->\n\n## COPY vs \\\\copy: The Path Problem\n\nBefore troubleshooting any error, confirm which command you're using. This distinction is the most commonly missed source of \"file not found\" and permission errors.\n\n**`COPY` (uppercase, no backslash):** Runs server-side. The file path is resolved by the PostgreSQL server process, not your local machine. The path must be accessible by the `postgres` OS user on the server. Use this when running SQL directly in the server environment.\n\n**`\\copy` (lowercase, with backslash):** Runs client-side via psql. The file path is resolved by your local machine. Use this when running psql from your workstation and the CSV is on your local disk.\n\n```sql\n-- Server-side (file must be on the database server)\nCOPY my_table FROM '/var/data/import.csv' WITH (FORMAT CSV, HEADER);\n\n-- Client-side (file is on your local machine)\n\\copy my_table FROM '/Users/yourname/import.csv' WITH (FORMAT CSV, HEADER);\n```\n\nIf you're getting `ERROR: could not open file for reading: No such file or directory` — switch to `\\copy`.\n\n## Fix 1: Data Type Mismatches\n\n`invalid input syntax for type` errors mean a CSV value cannot be converted to the target column's data type. PostgreSQL does not attempt type coercion during COPY — it either matches exactly or fails.\n\n**Common causes and fixes:**\n\n**Currency symbols in numeric columns** — `$1,250.00` cannot be parsed as NUMERIC. Strip all ` PostgreSQL COPY Error: Fix Invalid Input Syntax in CSV Import - SplitForge Blog , `€`, `£`, and thousands-separator commas from numeric fields before import.\n\n```\n❌ BAD row: 101,John Doe,$1,250.00,2026-03-15\n✅ FIXED row: 101,John Doe,1250.00,2026-03-15\n```\n\n**Null-like strings in numeric columns** — Values like `\"na\"`, `\"N/A\"`, `\"null\"`, `\"-\"`, or empty strings in numeric columns cause this error. Handle them explicitly:\n\n```\n❌ BAD row: 101,John Doe,na,2026-03-15\n✅ FIXED row: 101,John Doe,,2026-03-15 ← empty = NULL (with NULL '' option)\n```\n\nThen in your COPY command:\n\n```sql\nCOPY my_table FROM '/path/file.csv' \nWITH (FORMAT CSV, HEADER, NULL 'na');\n```\n\n**Header row included in data** — If your COPY command doesn't include `HEADER` but your CSV has a header row, PostgreSQL tries to parse the header as data values. Always include `HEADER` when your CSV has column headers:\n\n```\n❌ ERROR: COPY my_table FROM 'file.csv' WITH (FORMAT CSV);\n → \"invalid input syntax for integer: \"id\"\"\n✅ FIXED: COPY my_table FROM 'file.csv' WITH (FORMAT CSV, HEADER);\n```\n\nUse [SplitForge Data Validator](/tools/data-validator) to identify all type mismatch cells across your entire CSV before running COPY. It validates each column's values against a specified data type and flags non-conforming cells by row number.\n\n\u003c!-- [Screenshot: Data Validator showing type mismatch errors by row and column — alt text: \"SplitForge Data Validator flagging numeric type mismatch errors in CSV before PostgreSQL import\" — 800x400px] -->\n\n## Fix 2: Date Format Errors\n\nPostgreSQL's default date format is `YYYY-MM-DD` (ISO 8601). US-format dates (`MM/DD/YYYY`) and European dates (`DD/MM/YYYY`) are not interpreted correctly without explicit configuration.\n\n**Error:** `ERROR: invalid input syntax for type date: \"12/09/2011\"`\n\n**The exact problem:**\n```\n❌ BAD: id,name,event_date\n 1,Acme Corp,12/09/2011 ← MM/DD/YYYY fails by default\n✅ FIXED: id,name,event_date\n 1,Acme Corp,2011-12-09 ← YYYY-MM-DD works always\n```\n\n**Fix Option A — Pre-convert dates to ISO format:**\n\nConvert all dates to `YYYY-MM-DD` before running COPY. This is the most reliable approach and works regardless of PostgreSQL locale settings.\n\n**Fix Option B — Import as text, then cast:**\n\nImport the date column as TEXT, then cast in a post-import UPDATE:\n\n```sql\n-- Import into staging table with date as TEXT\nCOPY staging_table (id, name, date_text) \nFROM '/path/file.csv' WITH (FORMAT CSV, HEADER);\n\n-- Cast and insert into final table\nINSERT INTO final_table (id, name, event_date)\nSELECT id, name, TO_DATE(date_text, 'MM/DD/YYYY')\nFROM staging_table;\n```\n\n**Fix Option C — Set datestyle for the session:**\n\n```sql\nSET datestyle = 'ISO, MDY'; -- For MM/DD/YYYY inputs\n\\copy my_table FROM 'file.csv' WITH (FORMAT CSV, HEADER);\n```\n\nFor mixed date formats across different columns or rows, see our guide on [fixing mixed date formats in CSV files](/blog/csv-mixed-date-formats-same-column).\n\n## Fix 3: Column Count Errors\n\n`missing data for column` and `extra data after last expected column` both indicate row-level column count mismatches between the CSV and the table schema.\n\n**Most common cause — unquoted fields with embedded commas:**\n\nA CSV cell containing a comma must be wrapped in double quotes. If it isn't, PostgreSQL splits on the embedded comma and creates extra columns.\n\n```\n❌ BAD: John Doe,New York, NY,2026-03-15\n ↑ PostgreSQL sees 4 columns instead of 3\n\n✅ FIXED: John Doe,\"New York, NY\",2026-03-15\n ↑ PostgreSQL sees 3 columns correctly\n```\n\n**Second cause — unmatched double quotes causing row merges:**\n\nAn unclosed quote in one row causes PostgreSQL to continue reading subsequent rows as part of the same field. The result is rows that appear to have too few columns.\n\n**Fix — find the exact row:**\n\nPostgreSQL's error includes the line number. Count to that line in your CSV and inspect manually. For large files, validate structure with [SplitForge Data Validator](/tools/data-validator) to find all column count errors across the full file at once.\n\nFor a complete guide to column count mismatches, see [CSV column count mismatch fix](/blog/csv-column-count-mismatch-fix).\n\n## Fix 4: BOM Character on Line 1\n\nA UTF-8 BOM (Byte Order Mark, U+FEFF) is an invisible character that some Windows text editors and Excel add to the beginning of UTF-8 files. PostgreSQL reads it as part of the first field's value, causing the first field to contain `` + the actual value.\n\n**Symptom:** `ERROR: invalid input syntax for integer: \"3192\"` — The garbled character before `3192` is the BOM.\n\n**Fix Option A — Strip BOM in PostgreSQL 16+:**\n\n```sql\nCOPY my_table FROM '/path/file.csv' \nWITH (FORMAT CSV, HEADER, ENCODING 'UTF8BOM');\n```\n\n**Fix Option B — Strip BOM before import:**\n\nOpen the file in Notepad++ → Encoding → Convert to UTF-8 (not \"UTF-8 with BOM\"). Save and re-import.\n\n**Fix Option C — Use sed (Linux/Mac):**\n\n```bash\nsed -i '1s/^\\xEF\\xBB\\xBF//' yourfile.csv\n```\n\nThis strips the three BOM bytes from the first line.\n\nFor more on BOM issues in CSV files, see our [BOM CSV fix guide](/blog/bom-csv-fix-guide).\n\n## Fix 5: NULL and Empty Value Handling\n\nPostgreSQL's COPY interprets empty CSV fields as empty strings by default, not as NULL. If a column has a NOT NULL constraint or is typed as NUMERIC, an empty string fails.\n\n**Explicitly specify NULL representation:**\n\n```sql\n-- Treat empty strings as NULL\nCOPY my_table FROM '/path/file.csv' \nWITH (FORMAT CSV, HEADER, NULL '');\n\n-- Treat 'na' as NULL (for data from R, Python pandas exports)\nCOPY my_table FROM '/path/file.csv' \nWITH (FORMAT CSV, HEADER, NULL 'na');\n\n-- Treat 'NULL' string as NULL\nCOPY my_table FROM '/path/file.csv' \nWITH (FORMAT CSV, HEADER, NULL 'NULL');\n```\n\nFor NOT NULL columns, replace empty cells with a default value before importing. Use find-replace in a text editor or [SplitForge Data Cleaner](/tools/data-cleaner) to bulk-replace empty cells across large files.\n\n## Fix 6: Encoding Mismatch\n\nPostgreSQL defaults to the database's encoding, typically UTF-8. Files exported from Windows systems are often Windows-1252 or ANSI-encoded. Character mismatch produces `invalid byte sequence` errors.\n\n**Specify encoding explicitly:**\n\n```sql\nCOPY my_table FROM '/path/file.csv' \nWITH (FORMAT CSV, HEADER, ENCODING 'WIN1252');\n```\n\nSupported encoding names in PostgreSQL are listed in the official documentation at [PostgreSQL: Supported Character Sets](https://www.postgresql.org/docs/current/multibyte.html).\n\n## Pre-Import Validation Workflow\n\nRunning COPY directly on a large CSV and debugging errors line by line is slow. Use this workflow to validate before committing:\n\n1. **Run COPY on the first 100 rows** — Create a test CSV with just the header + first 100 rows and run COPY on it. This surfaces type and structure errors quickly.\n2. **Check column count** — `awk -F',' '{print NF}' file.csv | sort | uniq -c` shows how many rows have each column count. All rows should show the same number.\n3. **Check for BOM** — `hexdump -C file.csv | head -1` — If the first bytes are `ef bb bf`, there's a BOM.\n4. **Validate types before import** — Use [SplitForge Data Validator](/tools/data-validator) to check every column's values against expected types. For a 2-million-row file, this catches every error before COPY runs rather than after.\n\nFor related MySQL import errors using a similar LOAD DATA INFILE pattern, see [MySQL CSV import 1064 syntax error fix](/blog/mysql-csv-import-1064-syntax-error).\n\n## Additional Resources\n\n**PostgreSQL Official Documentation:**\n- [PostgreSQL COPY Command Reference](https://www.postgresql.org/docs/current/sql-copy.html) — Official COPY syntax, options, NULL handling, and encoding parameters\n- [PostgreSQL Supported Character Sets](https://www.postgresql.org/docs/current/multibyte.html) — Full list of encoding names for the ENCODING option\n- [PostgreSQL Data Types](https://www.postgresql.org/docs/current/datatype.html) — Type definitions and input format requirements\n\n**Standards:**\n- [RFC 4180: CSV Format Specification](https://datatracker.ietf.org/doc/html/rfc4180) — Official quoting and delimiter rules PostgreSQL COPY follows\n- [Unicode UTF-8 Standard](https://unicode.org/standard/standard.html) — UTF-8 and BOM specification\n\n## FAQ\n\n### What is the difference between COPY and \\\\copy in PostgreSQL?\n\n`COPY` (uppercase) runs server-side — the file path is resolved by the PostgreSQL server process and the file must be accessible by the `postgres` OS user on the server. `\\copy` (backslash, lowercase) runs client-side via psql — the file path is resolved on your local machine. Use `\\copy` when running psql from your workstation and the CSV is on your local disk.\n\n### How do I find which row is causing the COPY error?\n\nPostgreSQL's error output includes the exact line number in the CONTEXT line: `CONTEXT: COPY tablename, line 847, column colname: \"value\"`. Count to line 847 in your CSV (line 1 is the header if you used HEADER). Open the file in a text editor with line numbers enabled. For large files, validate the entire file with [SplitForge Data Validator](/tools/data-validator) to surface all errors at once rather than fixing one at a time.\n\n### Why does COPY fail when I import the file that PostgreSQL just exported?\n\nThe most common reason is BOM character addition. Some tools add a UTF-8 BOM when saving files. PostgreSQL 16+ added `ENCODING 'UTF8BOM'` to handle this. Another cause is exponential notation — PostgreSQL exports long numbers in standard format but some tools convert them to scientific notation on re-save.\n\n### Can I import a CSV into PostgreSQL without creating the table first?\n\nNo. COPY requires an existing table with defined column types. There is no \"create table from CSV\" native feature. You can use third-party tools like `pgfutter` or `csvkit`'s `csvsql` command to auto-generate a CREATE TABLE statement from a CSV header, then run COPY after the table exists.\n\n### How do I handle a CSV where some rows have more columns than others?\n\nPostgreSQL will error on the row count mismatch. Options: (1) use a staging table with all TEXT columns and insert with column selection after cleaning; (2) fix the CSV before import by quoting embedded commas and removing extra delimiters. Run [SplitForge Data Validator](/tools/data-validator) to locate all rows with wrong column counts before attempting COPY.\n\n### Why does PostgreSQL not import my date values correctly?\n\nPostgreSQL defaults to `YYYY-MM-DD` (ISO 8601) date format. US-format `MM/DD/YYYY` dates cause `invalid input syntax for type date` errors. Fix by setting `datestyle = 'ISO, MDY'` for the session, or convert all dates to `YYYY-MM-DD` before importing. The `TO_DATE()` function in a staging table approach gives the most control over format conversion.\n\n---\n\n## Validate Your CSV Before Running COPY\n\n✅ Find every type mismatch, column count error, and empty value before COPY runs\n✅ Identify BOM characters and encoding issues in seconds\n✅ Files validate locally in your browser — database credentials and data never leave your machine\n✅ Process 2-million-row files and get a complete error report in under 30 seconds\n\n**[Validate Your CSV Now →](https://splitforge.app/tools/data-validator)**\n"};
Navigated to blog › postgresql-csv-copy-error-fix
Back to Blog
csv-troubleshooting

PostgreSQL COPY Error: Fix Invalid Input Syntax in CSV Import

March 18, 2026
14
By SplitForge Team

Quick Answer

PostgreSQL's COPY command rejects CSV files for six predictable reasons: data type mismatches between CSV values and table column types, wrong column count per row, a BOM character at the start of the file, NULL values in NOT NULL columns, encoding mismatch, and the critical COPY vs \copy path distinction.

The fix: Pre-validate your CSV against your table schema before running COPY. Clean type mismatches, strip BOM characters, verify column counts, and handle NULL representations explicitly.

Why it happens: PostgreSQL's COPY is strict by design. Unlike spreadsheet importers, it does not attempt to cast or convert values — if a CSV cell contains "na" and the column is NUMERIC, COPY throws an error on that exact row. There is no partial import.


What PostgreSQL's Error Messages Actually Mean

ERROR: invalid input syntax for type integer: "value" (SQL state: 22P02) — A CSV cell contains text where the table column expects an integer. Check for header row included in data, currency symbols ($), commas in numbers, or text null representations like "na" or "NULL".

ERROR: invalid input syntax for type numeric: "$1.00" (SQL state: 22P02) — Currency-formatted values with $, , or commas cannot be parsed as NUMERIC. Strip formatting before import.

ERROR: invalid input syntax for type date: "12/09/2011" (SQL state: 22007) — Date format mismatch. PostgreSQL expects YYYY-MM-DD by default. US-format dates (MM/DD/YYYY) require explicit DATEFORMAT specification or pre-conversion.

ERROR: missing data for column "colname" (CONTEXT: COPY table, line N) — The row at line N has fewer comma-separated values than the table has columns. Check for truncated rows, mismatched delimiters, or unmatched quotes causing multiple rows to merge.

ERROR: extra data after last expected column — The row has more values than the table has columns. Check for embedded commas in unquoted fields.

ERROR: invalid input syntax for integer: "3192" (BOM character) — The invisible  (U+FEFF) character at the start of the file is being read as part of the first field's value. The file has a UTF-8 BOM that must be stripped.

ERROR: value too long for type character varying(N) — A text value exceeds the column's defined character limit. Run SELECT MAX(LENGTH(column_name)) FROM table_name to identify the longest values.

ERROR: null value in column "colname" of relation "table" violates not-null constraint — Empty CSV cells are being interpreted as NULL, but the column has a NOT NULL constraint. You must handle empty values explicitly.


Fast Fix (2 Minutes)

If your PostgreSQL COPY command just failed, try this first:

  1. Read the CONTEXT line — PostgreSQL tells you the exact line number. Count to that line in your CSV and inspect the value.
  2. Check for BOM — If the error is on line 1 and shows a garbled character before your first value, open the file in Notepad++ → Encoding → check if it shows "UTF-8-BOM". Remove it.
  3. Check column count — Run SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'yourtable' and verify it matches your CSV column count.
  4. Test with 5 rows — Create a 5-row test CSV with your cleanest data. If that imports, the problem is in a specific row of your full file.
  5. Add NULL AS option — If you have empty cells: COPY table FROM 'file.csv' WITH (FORMAT CSV, HEADER, NULL '') treats empty strings as NULL.

If the error persists on specific rows, continue below.


TL;DR: PostgreSQL COPY is all-or-nothing — one bad row fails the entire import. The most common causes are data type mismatches (text in numeric columns, wrong date formats), BOM characters making line 1 fail, and column count errors from unquoted fields with embedded commas. Validate your CSV with SplitForge Data Validator to find all errors before running COPY.


You're migrating 2 million rows of transaction data into PostgreSQL. You run the COPY command. Six seconds later: ERROR: invalid input syntax for type numeric: "na" CONTEXT: COPY transactions, line 847, column amount: "na". The import rolls back entirely. You're at zero rows imported.

PostgreSQL COPY is transactional. One bad row cancels every row. This is by design — partial imports create data integrity problems worse than failed ones. The solution is fixing the CSV before running COPY, not finding workarounds after.

Each error was reproduced using PostgreSQL 16 COPY command via psql, March 2026.


Error / SymptomRoot CauseFix
invalid input syntax for type integer: "value"Text/null in integer columnStrip currency, use NULL AS, check header inclusion
invalid input syntax for type numeric: "$1.00"Currency formatting in numeric columnRemove $, €, commas from numeric fields
invalid input syntax for type date: "MM/DD/YYYY"Wrong date format for PostgreSQLConvert to YYYY-MM-DD or use DATEFORMAT
missing data for column "colname"Fewer values than columns in that rowCheck for unmatched quotes causing row merges
extra data after last expected columnMore values than columns in that rowQuote fields containing commas
invalid input syntax for integer: "3192"UTF-8 BOM on first byte of fileStrip BOM before COPY
value too long for type character varying(N)Cell value exceeds column char limitCheck MAX(LENGTH()) and expand column or truncate
null value violates not-null constraintEmpty cells where NOT NULL expectedReplace empty cells with default values
unterminated CSV quoted fieldOpening quote with no closing quoteFind unmatched quotes in CSV — common in Excel exports with commas in values
unexpected end of dataLast row has fewer columns than expectedCheck for truncated file or missing trailing delimiter
invalid byte sequence for encoding "UTF8"File contains non-UTF8 bytesRe-encode file to UTF-8 before import
could not open file for reading: Permission deniedPostgreSQL server can't read the file pathUse \copy (client-side) or fix server file permissions
could not open file for reading: No such file or directoryWrong path or using COPY instead of \copySwitch to \copy or verify the server-side path
ERROR: deadlock detectedConcurrent import processes competingRun single-threaded; use \copy instead of parallel COPY
invalid input syntax for type boolean: "yes"PostgreSQL expects true/false, not yes/noReplace yes/no with true/false in CSV

COPY Format Options Quick Reference

OptionSyntaxWhen to use
FORMATFORMAT CSVAlways — specifies CSV parsing mode
HEADERHEADER or HEADER trueWhen first row is column headers
DELIMITERDELIMITER ','Non-comma delimiters (tab: DELIMITER E'\t')
NULLNULL 'na'When null values appear as strings (na, N/A, NULL)
ENCODINGENCODING 'WIN1252'Windows-exported files with non-UTF8 encoding
QUOTEQUOTE '"'Non-standard quote character (default is double-quote)
ESCAPEESCAPE '\'Non-standard escape character
FREEZEFREEZEBulk-load optimization (requires empty table, superuser)

Full example with common options:

COPY my_table FROM '/path/file.csv'
WITH (FORMAT CSV, HEADER, NULL '', ENCODING 'UTF8', DELIMITER ',');

How PostgreSQL COPY Compares to Other Import Systems

PlatformStrict on data types?Updates existing rows?Deduplicates?Safe date formatMax rows
PostgreSQL COPYYes — errors immediately, full rollbackN/A (append only)NoYYYY-MM-DDServer/memory limits
monday.comYes on labels/status — silent dropNo — append onlyNoYYYY-MM-DD8,000
Google SheetsNo — silent coercion/lossYes (paste over)NoYYYY-MM-DD safest10M cells
NotionPartial — silent dropNo — append onlyNoYYYY-MM-DD safest~50K practical
NetSuiteYes on references — row-level errorYes (Update mode)NoAccount date formatImport Assistant limits

PostgreSQL COPY is the strictest of all: one bad row in 2 million rows fails everything. The tradeoff is complete data integrity — there is no partial import.


Table of Contents


This guide is for: Database administrators, backend developers, and data engineers importing CSV data into PostgreSQL using the COPY command or pgAdmin's import feature. Basic SQL knowledge is assumed.


COPY vs \copy: The Path Problem

Before troubleshooting any error, confirm which command you're using. This distinction is the most commonly missed source of "file not found" and permission errors.

COPY (uppercase, no backslash): Runs server-side. The file path is resolved by the PostgreSQL server process, not your local machine. The path must be accessible by the postgres OS user on the server. Use this when running SQL directly in the server environment.

\copy (lowercase, with backslash): Runs client-side via psql. The file path is resolved by your local machine. Use this when running psql from your workstation and the CSV is on your local disk.

-- Server-side (file must be on the database server)
COPY my_table FROM '/var/data/import.csv' WITH (FORMAT CSV, HEADER);

-- Client-side (file is on your local machine)
\copy my_table FROM '/Users/yourname/import.csv' WITH (FORMAT CSV, HEADER);

If you're getting ERROR: could not open file for reading: No such file or directory — switch to \copy.

Fix 1: Data Type Mismatches

invalid input syntax for type errors mean a CSV value cannot be converted to the target column's data type. PostgreSQL does not attempt type coercion during COPY — it either matches exactly or fails.

Common causes and fixes:

Currency symbols in numeric columns$1,250.00 cannot be parsed as NUMERIC. Strip all $, , £, and thousands-separator commas from numeric fields before import.

❌ BAD row:   101,John Doe,$1,250.00,2026-03-15
✅ FIXED row: 101,John Doe,1250.00,2026-03-15

Null-like strings in numeric columns — Values like "na", "N/A", "null", "-", or empty strings in numeric columns cause this error. Handle them explicitly:

❌ BAD row:   101,John Doe,na,2026-03-15
✅ FIXED row: 101,John Doe,,2026-03-15   ← empty = NULL (with NULL '' option)

Then in your COPY command:

COPY my_table FROM '/path/file.csv' 
WITH (FORMAT CSV, HEADER, NULL 'na');

Header row included in data — If your COPY command doesn't include HEADER but your CSV has a header row, PostgreSQL tries to parse the header as data values. Always include HEADER when your CSV has column headers:

❌ ERROR: COPY my_table FROM 'file.csv' WITH (FORMAT CSV);
          → "invalid input syntax for integer: "id""
✅ FIXED:  COPY my_table FROM 'file.csv' WITH (FORMAT CSV, HEADER);

Use SplitForge Data Validator to identify all type mismatch cells across your entire CSV before running COPY. It validates each column's values against a specified data type and flags non-conforming cells by row number.

Fix 2: Date Format Errors

PostgreSQL's default date format is YYYY-MM-DD (ISO 8601). US-format dates (MM/DD/YYYY) and European dates (DD/MM/YYYY) are not interpreted correctly without explicit configuration.

Error: ERROR: invalid input syntax for type date: "12/09/2011"

The exact problem:

❌ BAD:   id,name,event_date
          1,Acme Corp,12/09/2011     ← MM/DD/YYYY fails by default
✅ FIXED: id,name,event_date
          1,Acme Corp,2011-12-09     ← YYYY-MM-DD works always

Fix Option A — Pre-convert dates to ISO format:

Convert all dates to YYYY-MM-DD before running COPY. This is the most reliable approach and works regardless of PostgreSQL locale settings.

Fix Option B — Import as text, then cast:

Import the date column as TEXT, then cast in a post-import UPDATE:

-- Import into staging table with date as TEXT
COPY staging_table (id, name, date_text) 
FROM '/path/file.csv' WITH (FORMAT CSV, HEADER);

-- Cast and insert into final table
INSERT INTO final_table (id, name, event_date)
SELECT id, name, TO_DATE(date_text, 'MM/DD/YYYY')
FROM staging_table;

Fix Option C — Set datestyle for the session:

SET datestyle = 'ISO, MDY'; -- For MM/DD/YYYY inputs
\copy my_table FROM 'file.csv' WITH (FORMAT CSV, HEADER);

For mixed date formats across different columns or rows, see our guide on fixing mixed date formats in CSV files.

Fix 3: Column Count Errors

missing data for column and extra data after last expected column both indicate row-level column count mismatches between the CSV and the table schema.

Most common cause — unquoted fields with embedded commas:

A CSV cell containing a comma must be wrapped in double quotes. If it isn't, PostgreSQL splits on the embedded comma and creates extra columns.

❌ BAD:   John Doe,New York, NY,2026-03-15
          ↑ PostgreSQL sees 4 columns instead of 3

✅ FIXED: John Doe,"New York, NY",2026-03-15
          ↑ PostgreSQL sees 3 columns correctly

Second cause — unmatched double quotes causing row merges:

An unclosed quote in one row causes PostgreSQL to continue reading subsequent rows as part of the same field. The result is rows that appear to have too few columns.

Fix — find the exact row:

PostgreSQL's error includes the line number. Count to that line in your CSV and inspect manually. For large files, validate structure with SplitForge Data Validator to find all column count errors across the full file at once.

For a complete guide to column count mismatches, see CSV column count mismatch fix.

Fix 4: BOM Character on Line 1

A UTF-8 BOM (Byte Order Mark, U+FEFF) is an invisible character that some Windows text editors and Excel add to the beginning of UTF-8 files. PostgreSQL reads it as part of the first field's value, causing the first field to contain  + the actual value.

Symptom: ERROR: invalid input syntax for integer: "3192" — The garbled character before 3192 is the BOM.

Fix Option A — Strip BOM in PostgreSQL 16+:

COPY my_table FROM '/path/file.csv' 
WITH (FORMAT CSV, HEADER, ENCODING 'UTF8BOM');

Fix Option B — Strip BOM before import:

Open the file in Notepad++ → Encoding → Convert to UTF-8 (not "UTF-8 with BOM"). Save and re-import.

Fix Option C — Use sed (Linux/Mac):

sed -i '1s/^\xEF\xBB\xBF//' yourfile.csv

This strips the three BOM bytes from the first line.

For more on BOM issues in CSV files, see our BOM CSV fix guide.

Fix 5: NULL and Empty Value Handling

PostgreSQL's COPY interprets empty CSV fields as empty strings by default, not as NULL. If a column has a NOT NULL constraint or is typed as NUMERIC, an empty string fails.

Explicitly specify NULL representation:

-- Treat empty strings as NULL
COPY my_table FROM '/path/file.csv' 
WITH (FORMAT CSV, HEADER, NULL '');

-- Treat 'na' as NULL (for data from R, Python pandas exports)
COPY my_table FROM '/path/file.csv' 
WITH (FORMAT CSV, HEADER, NULL 'na');

-- Treat 'NULL' string as NULL
COPY my_table FROM '/path/file.csv' 
WITH (FORMAT CSV, HEADER, NULL 'NULL');

For NOT NULL columns, replace empty cells with a default value before importing. Use find-replace in a text editor or SplitForge Data Cleaner to bulk-replace empty cells across large files.

Fix 6: Encoding Mismatch

PostgreSQL defaults to the database's encoding, typically UTF-8. Files exported from Windows systems are often Windows-1252 or ANSI-encoded. Character mismatch produces invalid byte sequence errors.

Specify encoding explicitly:

COPY my_table FROM '/path/file.csv' 
WITH (FORMAT CSV, HEADER, ENCODING 'WIN1252');

Supported encoding names in PostgreSQL are listed in the official documentation at PostgreSQL: Supported Character Sets.

Pre-Import Validation Workflow

Running COPY directly on a large CSV and debugging errors line by line is slow. Use this workflow to validate before committing:

  1. Run COPY on the first 100 rows — Create a test CSV with just the header + first 100 rows and run COPY on it. This surfaces type and structure errors quickly.
  2. Check column countawk -F',' '{print NF}' file.csv | sort | uniq -c shows how many rows have each column count. All rows should show the same number.
  3. Check for BOMhexdump -C file.csv | head -1 — If the first bytes are ef bb bf, there's a BOM.
  4. Validate types before import — Use SplitForge Data Validator to check every column's values against expected types. For a 2-million-row file, this catches every error before COPY runs rather than after.

For related MySQL import errors using a similar LOAD DATA INFILE pattern, see MySQL CSV import 1064 syntax error fix.

Additional Resources

PostgreSQL Official Documentation:

Standards:

FAQ

COPY (uppercase) runs server-side — the file path is resolved by the PostgreSQL server process and the file must be accessible by the postgres OS user on the server. \copy (backslash, lowercase) runs client-side via psql — the file path is resolved on your local machine. Use \copy when running psql from your workstation and the CSV is on your local disk.

PostgreSQL's error output includes the exact line number in the CONTEXT line: CONTEXT: COPY tablename, line 847, column colname: "value". Count to line 847 in your CSV (line 1 is the header if you used HEADER). Open the file in a text editor with line numbers enabled. For large files, validate the entire file with SplitForge Data Validator to surface all errors at once rather than fixing one at a time.

The most common reason is BOM character addition. Some tools add a UTF-8 BOM when saving files. PostgreSQL 16+ added ENCODING 'UTF8BOM' to handle this. Another cause is exponential notation — PostgreSQL exports long numbers in standard format but some tools convert them to scientific notation on re-save.

No. COPY requires an existing table with defined column types. There is no "create table from CSV" native feature. You can use third-party tools like pgfutter or csvkit's csvsql command to auto-generate a CREATE TABLE statement from a CSV header, then run COPY after the table exists.

PostgreSQL will error on the row count mismatch. Options: (1) use a staging table with all TEXT columns and insert with column selection after cleaning; (2) fix the CSV before import by quoting embedded commas and removing extra delimiters. Run SplitForge Data Validator to locate all rows with wrong column counts before attempting COPY.

PostgreSQL defaults to YYYY-MM-DD (ISO 8601) date format. US-format MM/DD/YYYY dates cause invalid input syntax for type date errors. Fix by setting datestyle = 'ISO, MDY' for the session, or convert all dates to YYYY-MM-DD before importing. The TO_DATE() function in a staging table approach gives the most control over format conversion.


Validate Your CSV Before Running COPY

Find every type mismatch, column count error, and empty value before COPY runs
Identify BOM characters and encoding issues in seconds
Files validate locally in your browser — database credentials and data never leave your machine
Process 2-million-row files and get a complete error report in under 30 seconds

Continue Reading

More guides to help you work smarter with your data

ai-data-prep

AI-Ready Data Checklist: 10 Things to Verify Before Upload (2026)

Before uploading to ChatGPT, Claude, or a fine-tuning API, run through this 10-point checklist. UTF-8 encoding, clean headers, PII removed, size within limits.

Read More
ai-data-prep

Convert Excel to JSON for AI APIs and LLM Pipelines (2026)

AI APIs and LLM pipelines expect JSON, not spreadsheets. Fine-tuning needs JSONL; direct prompts take arrays. Convert locally — no upload, no conversion server.

Read More
ai-data-prep

Prepare Data for AI: The Complete Guide (Privacy-First, 2026)

How to prepare a CSV or Excel file for ChatGPT, Claude, or an AI API — encoding, PII, format, size, and privacy. The complete local-first prep workflow.

Read More