Feed a language model a CSV of ten thousand rows and it will confidently summarize it after reading roughly none of those rows in the way a spreadsheet function would. Depending on the interface, it may run actual code against the data, or it may pattern-match against a truncated sample and generate plausible-sounding statistics that don’t correspond to the file at all. This is the single most common source of bad data analysis output, and almost nobody accounts for it in their prompts.
Data analysis prompting fails differently than writing or coding prompts. The model can produce fluent, confident, well-formatted output that is quietly wrong at the level of the underlying numbers, and there’s no immediate tell — a bad paragraph reads badly, but a wrong average looks exactly like a right one. This post walks through the failure modes I see most often, organized as symptom, cause, and fix, so you can diagnose a bad output instead of just regenerating and hoping for something better.
Symptom: The numbers in the response don’t match your actual dataset
You ask for the average order value or the correlation between two columns, and the figure that comes back is close, or plausible, or round in a way that raw data rarely is — but when you check it against the source, it’s wrong.
Cause: The model wasn’t executing analysis against your data at all. Depending on the tool, it may have summarized a truncated preview of the file, or it may have generated a statistically typical-looking number based on what values like that usually look like in similar datasets, without any actual computation happening.
Fix: Explicitly require code execution, not estimation. In tools that support it — ChatGPT’s Code Interpreter / Advanced Data Analysis, Claude’s analysis tool, or any agent wired to a Python sandbox — state directly: “Write and run Python code to calculate this; do not estimate.” Then ask it to print the intermediate result, like the row count it operated on, so you can sanity-check that it processed the full dataset rather than a sample. If the interface has no code execution at all, treat every numeric claim it gives you as a hypothesis to verify elsewhere, not a result.
Symptom: The model summarizes the whole file when you only wanted one slice of it
You wanted the trend for a single region or a single product category, and instead you got an overview of the entire dataset with your target buried in one line near the bottom.
Cause: No explicit filter was defined, so the model treated the question as a request for a general summary — the same default-to-generic behavior you’d see in any underspecified prompt, just applied to rows instead of prose.
Fix: State the filter as a discrete condition, the way you’d write a WHERE clause. “Filter to rows where region == 'Northeast' before computing anything else.” “Restrict this analysis to the last fiscal quarter.” Naming the exact subset up front keeps the model from re-deriving your intent from context and getting it half right.
Symptom: The analysis is correct but you can’t tell how it got there
The final number looks reasonable, but there’s no way to check the logic — was it grouped by the right field, did it exclude nulls, did it handle duplicate rows the way you’d expect?
Cause: You asked for a conclusion without asking for the method. The model has no default obligation to show its work, so it collapses straight to the answer, the same way it collapses to generic prose when no format is specified.
Fix: Ask for the method as its own required output, not an afterthought. “Show the exact grouping and aggregation logic used, and print the code alongside the result.” This also makes errors easier to catch — a wrong GROUP BY column is obvious in code in a way it’s invisible in a single summary sentence.
Symptom: Missing or malformed values quietly change the result
Your dataset has nulls, blank strings, or a stray “N/A” scattered through a numeric column, and the summary statistics don’t account for them — or worse, they silently get coerced into zero and skew the average.
Cause: No instruction was given for how to handle missing data, so the model — or the code it generated — defaulted to whatever the underlying library does automatically, which varies by tool and is rarely the behavior you’d choose deliberately.
Fix: Specify null-handling explicitly, the same way you’d specify it in a data pipeline spec. “Exclude rows with missing values in the revenue column before calculating the mean, and report how many rows were dropped.” That last clause matters — the row count dropped is your check that the exclusion actually happened as described.
Symptom: The output is a wall of text when you needed something you could act on
You get three paragraphs of prose describing trends in the data, but no table, no ranked list, no chart — just narrative description of numbers you now have to extract by hand.
Cause: Format was never specified for the deliverable, and prose is the default completion shape for most models absent an explicit structural instruction.
Fix: Name the output artifact directly. “Return the top 5 products by revenue as a markdown table with columns Product, Revenue, and Units Sold.” If the tool supports chart generation, ask for the chart type by name — “a bar chart, not a line chart” — since an unspecified visualization request tends to default to whatever’s easiest to generate rather than whatever best represents your data.
Symptom: A follow-up question resets context you already established
Early in the session you asked it to exclude test accounts or filter to active users. Three prompts later, a new query includes them again as if the earlier constraint never existed.
Cause: Same context dilution problem you’d see in any long conversation — the original filter is still technically in the context window, but its relative weight against everything asked since has dropped, especially once new code and outputs have been generated in between.
Fix: Re-state standing constraints on any prompt where they matter, rather than assuming persistence. “Continue applying the earlier filter excluding test accounts” costs one sentence and removes the ambiguity. For long analytical sessions, it’s worth restating your two or three core constraints at the start of each new question rather than trusting the model to carry them forward indefinitely.
Symptom: The model recommends an analysis method that doesn’t fit your data
You asked for “insights” and got a correlation coefficient run on categorical data, or a mean calculated on a column that’s really an ID field, not a quantity.
Cause: An open-ended request for “insights” or “analysis” gives the model no constraint on which statistical method applies, so it defaults to the most common technique in its training distribution rather than the one appropriate to your variable types.
Fix: Either name the method yourself or ask the model to justify its choice before running anything. “Before calculating anything, tell me which columns are categorical versus numeric, and propose an appropriate method for comparing them.” This adds one extra round trip but catches a mismatched method before it produces a confidently wrong result you might not think to question.
A Quick Reference for Diagnosing Bad Analysis Output
| Symptom | Likely Cause | Fix |
|---|---|---|
| Numbers don’t match the source data | No real code execution | Require Python execution and printed row counts |
| Wrong subset summarized | No filter specified | State the filter condition explicitly |
| Result with no visible logic | Method not requested | Ask for grouping/aggregation code alongside the answer |
| Nulls skewing results | No missing-data handling defined | Specify exclusion rule and request a dropped-row count |
| Wall of prose, no usable artifact | No output format specified | Name the exact table, list, or chart type wanted |
| Old filters silently dropped | Context dilution over a long session | Restate standing constraints on relevant follow-ups |
| Wrong statistical method applied | Open-ended “insights” request | Ask for variable types and method justification first |
The through-line across all seven of these is the same: a language model doing data analysis is not a calculator, and treating it like one without verification is how confidently wrong numbers end up in a report. Every fix above amounts to the same discipline — specify the operation, specify the scope, and ask to see the work, rather than trusting a clean-looking output at face value.
Before you trust the next number a model hands you from your own data, ask it to show you the code. If it can’t, or won’t, that’s your answer about how much weight that number deserves.
🔗 Recommended Reading
- Function Calling and Tool Use in LLMs: A Practical Guide
- Prompt Engineering for AI Video Generation: A Sora, Runway, and Pika Guide
- Prompt Engineering for Multimodal AI: Working With Images, Text, and Voice
- AI Prompt Security Best Practices for Enterprise Teams
- Prompt Versioning: How to Track and Manage Changes to Your AI Prompts Over Time