Back to blog
Engineering20 min read

Why Does AI Misread My Table or CSV?

AI misreads a table for eight unrelated reasons, from a paste that lost its columns to a screenshot it has to OCR. The causes, 28 repair prompts, and the check that catches a silent misread.

NH
Nafiul Hasan
Founder, Prompt Architects

TL;DR: A model misreads a table for eight unrelated reasons: a paste that lost its columns, a screenshot it must OCR, an unclear header, an ambiguous delimiter, regional number formats, blank cells, a totals row, and sheer length. Each has a different fix. Worst of all, a misread looks exactly like a correct read.

Why does AI misread my table or CSV?

Because the grid you are looking at and the text the model receives are not the same object, and nothing in the chat window tells you where they diverged.

There is no single cause, which is why generic advice fails here. Eight distinct things go wrong and the fix for one does nothing for the others: structure destroyed in transit, a screenshot that forces optical character recognition, a merged cell or title row hiding the real header, a guessed delimiter, a regional number format that inverts a value, a blank cell meaning three different things, a totals row counted as data, and a long table getting uneven attention.

Underneath all eight sits the fact that makes this genuinely dangerous.

This post is about the input side. Asking a model to produce a table is a different problem with different failure modes, covered in how to prompt for tables and structured data.

Where did my columns go when I pasted the table?

Into the clipboard. A spreadsheet range pasted into a chat box passes through a plain-text conversion that frequently collapses tabs into single spaces and wraps long rows onto the next line.

What arrives is not a grid. It is run-together text with no column boundaries, from which the model reconstructs a table by pattern-matching. Sometimes that is perfect. Sometimes a two-word city name becomes two columns and every field to its right shifts by one.

The repair is to stop asking for analysis and ask for a parse report first.

Do not analyse this data yet.

Here is a table I pasted. Tell me only:
1. How many columns you detect.
2. The header names, in order, exactly as written.
3. The first three data rows, one per line, with fields separated by " | ".
4. Every row whose field count differs from the header's field count,
   quoted verbatim.
5. Anything you had to guess about where one column ends and the next begins.

If you cannot determine the column boundaries with confidence, say so and stop.

If the column count is wrong, do not argue with it. Re-send the data in a form that carries its own boundaries.

I am re-sending the same data as CSV inside a code block. Ignore the earlier
paste entirely. Fields are comma-separated, quoted where they contain commas,
one record per line, first line is the header.

Better still, upload the file. A .csv preserves what a clipboard destroys, and OpenAI's guidance is explicit that when exact values matter you should "upload a spreadsheet or text-based file instead" of an image (Data analysis with ChatGPT, read August 29, 2026).

Why is a screenshot of a table the worst possible input?

Because the model is no longer reading data. It is reading pixels, and a misread digit is indistinguishable from a correct one. Both vendors say so themselves. OpenAI: "ChatGPT may not reliably extract exact values from image-based tables, scanned files, or files with complex visual layouts." Anthropic's vision documentation lists under limitations that "Claude might hallucinate or make mistakes when interpreting low-quality, rotated, or very small images under 200 pixels", and closes with the instruction not to use Claude "for tasks requiring perfect precision or sensitive image analysis without human oversight" (Vision, read August 29, 2026).

If a screenshot is genuinely all you have, force the uncertainty into the open rather than hoping it is absent.

This is a photograph of a table. Transcribe it, do not analyse it.

Rules:
- Output CSV only, no commentary.
- Reproduce every character exactly as printed, including currency symbols
  and separators. Do not normalise anything.
- Where a character is unclear, output the cell as UNCLEAR:<your best guess>
- Do not infer a value from the row total or from neighbouring rows.
- After the CSV, list every UNCLEAR cell with its row and column.
Before you transcribe: how many rows and how many columns can you see?
Is any part of the table cut off at an edge of the image? Answer those two
questions first and wait.

The general craft of prompting with pictures is covered in how to prompt with images. The rule specific to tables is simpler: if the numbers matter, do not send a picture of them.

How does the model decide which row is the header?

It guesses, and it guesses from position: the first line it meets is the header unless something obvious contradicts that.

So three common spreadsheet habits break it. A title row above the header (a Q3 Sales Report line, then a blank row, then the real headers) hands the model a one-cell header. Merged cells spanning two columns collapse to one value and shift everything after. A two-row header, category on top and unit underneath, flattens into one row of half-names.

OpenAI's guidance for preparing spreadsheets says to use "Descriptive column headers in the first row" and "One row per record", and to avoid "Multiple unrelated tables in one sheet", "Empty rows or columns that split the data" and "Images that contain values ChatGPT needs to analyze". That is a vendor naming the shapes it cannot reliably parse. Fix the sheet first. When you cannot, state the geometry.

Structure of the file I am sending:
- Rows 1 to 3 are a title block. Ignore them completely.
- Row 4 is the header.
- Rows 5 to 412 are data.
- Row 413 is a totals row. Exclude it from every calculation.
- Columns C and D are merged in the header only; treat them as
  "revenue_gross" and "revenue_net".

Confirm you have applied all five points before answering anything.
This table has a two-row header. Flatten it into single names by joining the
top-row category and the second-row label with an underscore, then show me the
flattened header list and stop.
Strip any row that is not a data record: title rows, blank spacer rows,
repeated header rows in the middle of the file, and section subtotals.
List every row you removed, quoted, before you continue.

Which delimiter is your file actually using?

Possibly not a comma, and the format has never had a real standard to appeal to. RFC 4180 says so in its own opening: "there is no formal specification in existence, which allows for a wide variety of interpretations of CSV files". It documents conventions rather than mandating them. Three matter here: "Fields containing line breaks (CRLF), double quotes, and commas should be enclosed in double-quotes", a quote inside a quoted field "must be escaped by preceding it with another double quote", and "Each line should contain the same number of fields throughout the file" (RFC 4180, read August 29, 2026).

Then there is the regional problem, which Microsoft documents directly. "When you save a workbook as a .csv file, the default list separator (delimiter) is a comma. You can change this to another separator character using Windows Region settings." And in the other direction, if you want semicolons, Microsoft suggests you "consider changing the default decimal separator to a comma", which "forces Excel to use a semi-colon for the list separator" (Import or export text files, read August 29, 2026).

So a file exported on a colleague's machine can arrive semicolon-delimited with commas as decimal points, and every number in it reads as garbage unless you say so.

Before parsing: report the delimiter you detected, the quote character, the
line ending, and the number of fields on the header line. Then report the
count of lines whose field count does not match the header. Stop there.
This file is semicolon-delimited. Decimal separator is a comma, thousands
separator is a period. Quoted fields may contain semicolons. Parse on that
basis and echo back row 1 and row 2 as you understand them.
One column contains free text that includes commas inside double quotes.
Confirm you are treating quoted commas as literal characters and not as
field separators, and show me the parsed value of the longest text field.

Why are the numbers wrong when the parse looked right?

Because a correctly located cell can still hold a value the model read incorrectly. The grid and the numbers fail independently. Six formats do most of the damage. A thousands separator (1,240) can be split as a delimiter. A decimal comma (3,50 for three and a half) can be read as three thousand five hundred. A currency symbol or trailing percent sign turns a numeric column into text, so sums skip it or concatenate. Percentages as text (12%) versus as a fraction (0.12) differ by a factor of a hundred. 03/04/2026 is genuinely ambiguous, and the model resolves it by convention rather than knowledge. Accounting-style negatives, (1,240), are frequently read as positive.

Number and date conventions for this data, applied to every column:
- Thousands separator: comma. Decimal separator: period.
- Currency columns are in USD; the symbol is display only, strip it.
- Percent columns are stored as text with a trailing %; convert to a fraction.
- Parentheses around a number mean negative.
- All dates are DD/MM/YYYY.
- Blank means "not recorded". It does not mean zero.

Restate these six rules in your own words, then wait for my question.
List every column, and for each one state the data type you inferred
(integer, decimal, currency, percentage, date, text, boolean) and the single
value you used to decide. Do not convert anything yet.
Flag any date in this file that is ambiguous between DD/MM and MM/DD
(that is, where both day and month are 12 or lower). List them by row.
Do not resolve them; I will tell you the convention.

Why format alone can wreck arithmetic goes deeper, into how numbers reach a model at all, and we told that story in why AI gets dates and arithmetic wrong.

What does a blank cell mean, and what is that last row?

Nobody knows, which is the problem. A blank can mean zero, unknown, not applicable, or that the export dropped it, and those four produce four different averages. The model picks one silently, usually excluding blanks as missing, which is right for unknown and wrong for zero.

The trailing totals row is the same error wearing a different hat. It looks like a data row, parses like a data row, and including it in a sum doubles the sum. Mid-file subtotals are worse, because they are harder to spot in the output.

For each column, count and report: populated cells, empty cells, and cells
containing a placeholder such as N/A, NA, -, null, none, or 0 where zero is
implausible. Report counts only. Do not fill anything in.
In this dataset, an empty cell in "units_returned" means zero. An empty cell
in "customer_segment" means unknown and must be excluded from any grouping.
Apply that distinction and tell me how many rows each rule affected.
Identify any row that is an aggregate rather than a record: grand totals,
subtotals, averages, or section summaries. Quote each one and confirm you
have excluded it. Then state the number of true data rows you will use.

Why does the middle of a long table get the least attention?

Because attention over a long input is not uniform, and vendors admit it rather than deny it. Google's Gemini Apps help page describes the failure precisely, for oversized uploads: "If you try to upload a file that is too large, Gemini may provide a response that misses connections or details throughout the content. This is most relevant for prompts that require attention to many details scattered throughout large file(s)" (Upload and analyze files in Gemini Apps, read August 29, 2026). OpenAI puts it as a symptom: "A file may upload successfully but still be too large, complex, image-heavy, or poorly structured for complete analysis."

That is the shape of a long-table misread. Rows near the top and bottom get quoted accurately; rows in the middle get summarised, approximated or skipped, and the summary reads perfectly well.

Width does its own damage. Forty columns means most of the context window goes on fields your question never touches, diluting the ones it does.

Do not summarise. Process rows 1 to 100 only. Output the row number and the
value of "invoice_total" for each. Then stop and wait; I will ask for the
next block.
Before answering: state the total number of data rows you can see, then quote
the first row and the last row verbatim. If your row count differs from 412,
say so and stop.
I only need four columns: order_id, order_date, region, net_amount.
Discard every other column before you begin. Confirm the four you kept.

What is the transcribe-then-reason pattern?

It is the one habit that turns an invisible misread into a visible one. You split the work into a parse step you can check and an analysis step that depends on it.

The order matters. Ask a question and get an answer, and you cannot audit the parse, because the parse is not in the output. Make the model publish it first and you can compare it to the source in about fifteen seconds, where a wrong column count or a missing row is obvious.

STEP 1 OF 2. Transcription only. Do not analyse, summarise, or calculate.

Echo back exactly:
- Number of columns, and the header names in order.
- Number of data rows, excluding any header, title or totals rows.
- Row 1, the middle row, and the final data row, verbatim, field by field.
- The data type you inferred for each column.
- Every assumption you made about delimiters, dates, blanks or number formats.
- Anything in the file you could not parse.

Then stop. I will confirm before you continue.
STEP 2 OF 2. I have verified your transcription and it is correct.
Now answer the question below using ONLY the parsed values you echoed above.
If any figure you need is not in that transcription, say so instead of
recomputing it from the raw file.

Question: <your question>

Two checks on top of that, both cheap.

Pick five rows at random. For each, quote the raw line from the source file
and then the parsed values you derived from it, side by side. I will check
them against my copy.
For every number in your answer, cite the row and the column it came from.
If a number is derived, show the arithmetic and name every input cell.
Do not include any figure you cannot trace to a cell.
Recompute the headline figure a second way, using a different route through
the data (for example, sum the parts instead of reading the total). Report
both results. If they disagree, do not reconcile them: show me both and
tell me which rows differ.

Should the model be doing the arithmetic at all?

For real arithmetic over real data, no. A spreadsheet formula or a short script is the right tool, and the deciding property is auditability rather than accuracy: a formula can be inspected, re-run and handed to someone else.

Anthropic states the position plainly: "Claude can process mathematical equations and perform calculations, but complex or mission-critical calculations should be verified using specialized mathematical software or manual methods" (How does Claude handle mathematical equations and calculations?, read August 29, 2026).

Code execution narrows the gap without closing it. OpenAI documents that "For some data-analysis tasks, ChatGPT writes and runs Python code in a stateful Jupyter notebook environment", and then adds the instruction most people skip: "When ChatGPT uses Python for analysis, review the generated code, outputs, and assumptions before relying on the result." The code runs correctly on whatever it parsed. If the parse took the totals row as data, the answer is wrong in a way no runtime error reveals.

What a model is genuinely good at is describing the data, reshaping it, explaining what a column means, spotting a suspicious pattern, and writing the formula you then run yourself.

Do not calculate the answer. Write the Excel formula that calculates it,
assuming the header is in row 1 and data runs to row 412. Explain what each
argument does, then list two ways the formula could give a wrong result
on this data.
Write a Python script using pandas that answers the question below. Include
the exact read_csv call with delimiter, decimal, thousands and date-format
arguments set for this file. Print the row count after loading so I can
check it. Do not run it; I will run it myself.
Run code to answer this, and after the result, print: the number of rows
loaded, the dtypes of every column, the count of nulls per column, and the
first and last row. I want to check the load before I trust the number.
Convert this table to JSON records with one object per row and the header
names as keys. Do not change any value. Do not add fields.

If structured records are where you are heading, the schema-first route is in our JSON prompt generator.

Which file limits do the vendors actually publish?

They differ sharply by surface, and an API's published limit does not apply to the consumer app of the same brand.

The Gemini API states "Gemini supports PDF files up to 50MB or 1000 pages" and warns that "You can also pass non-PDF documents in the same way but Gemini will see them as normal text which will eliminate context like charts or formatting". The consumer app publishes none of that. Its help page says only that "Gemini Apps support most file types", with "Up to 10 files (subject to availability) can be uploaded in the same prompt" and 100MB per non-video file. One brand, two products, incomparable numbers.

Read on each vendor's own documentation, August 29, 2026. Figures are per surface and do not transfer between them.
FeatureChatGPT appClaude appGemini appGemini API
Spreadsheet formats named in docs.xls, .xlsx, .csvCSV listed; XLSX requires code execution enabledNot itemised, "most file types"Non-PDF is seen as normal text
Published size cap~50MB for CSV/spreadsheets, 512MB per file overall500MB per chat upload, 30MB per project file100MB per file, 2GB per videoPDF 50MB or 1,000 pages
Files per prompt or chat80 uploads per 3 hours, 3/day on FreeUp to 20 files per chatUp to 10 files per promptNot published as a count
Runs code on your dataYes, Python in a Jupyter environmentYes, an account setting you enableCharting documented; code execution not statedYes, Python, 30-second runtime
Warns about extraction accuracyYes, explicitly, for image-based tablesNot on this page; the API vision docs doYes, for oversized files missing detailsNon-PDF input loses charts and formatting
Documents what a blank cell meansNot publishedNot publishedNot publishedNot published

Three more per-surface facts. Anthropic's upload page says XLSX requires that "You must enable code execution and file creation in your account", and that "For non-PDF documents: Claude extracts text only from these files. If they contain embedded images, Claude won't be able to read or interpret them" (Upload files to Claude, read August 29, 2026). OpenAI says the same of non-visual retrieval: "ChatGPT will extract digital text from the file and discard any images" (File Uploads FAQ, read August 29, 2026). And the Gemini API notes that "Code execution works best with text and CSV files", with a 30-second runtime (Code execution, read August 29, 2026).

Not published on any of these surfaces: how a blank cell is interpreted, how a merged cell is flattened, which row is chosen as the header, what happens to a trailing totals row, or the accuracy of value extraction from a table image. Those are the five things you most want to know, and every one is undocumented. Which is exactly why the transcribe-then-reason step is not optional.

What none of this fixes

None of it makes a misread impossible. It makes a misread visible, which is a smaller and more honest promise. It does nothing about a model being wrong for reasons unrelated to your file, the general case we treat in red-team your own prompt before you trust the output. And if you run the same analysis weekly, the answer is a script and a scheduler, not a better prompt.

The short version: send the file, not a picture of it. Declare the header, the delimiter, the number formats and what a blank means. Make it transcribe before it reasons. Get the formula, not the answer. Then check five values against the source yourself, every time, because the model cannot tell you which five it got wrong.

Prompt Architects generates prompts. It does not process your files, parse your CSV or touch your data, and any tool claiming to fix a misread without you reading the source is selling you something. What our prompt enhancer does is keep blocks like the format declaration and the two-step transcription pattern one click away rather than retyped from memory at the moment a number mattered. The Free plan includes "5 prompt enhancements per day, forever" per our FAQ, though the pricing page currently shows only the paid tiers, so take that figure from the FAQ.

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.

Create An Account

Frequently asked questions

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.

Create An Account