Claude Fabricated 190 Records and Debunked Itself — Strong at Self-Correction, but Fails at 'Taking a Look'


I never intervened in this entire process—the one who caught the error was Claude itself.

The coupons project had just been deployed, entering the data exploration phase to see exactly what the coupon aggregation site contained. The first tool Claude picked up was WebFetch, a scraping method that allows the model to retrieve a webpage and summarize it along the way. It returned a seemingly complete list: about 190 coupons, accompanied by a few “discoveries.” There were duplicate codes (26551 and 26953 each appeared twice), one record where the price equaled the original price (16486 was 138/138), and every record included an expiration date.

Based on this, Claude reported “about 190 records” to me and was already preparing to modify the schema based on these findings. The item about duplicate codes was particularly convincing because it perfectly corroborated a hardcoded rule in the project’s CLAUDE.md: code is not a unique key—different coupons might share the same code, so the code cannot be used as an identifier.

If it had stopped there, this would have been just an ordinary story of “an AI hallucination almost altering a database schema.” But it did not stop there.

Claude Turned Back on Its Own

Claude switched to curl and retrieved the raw HTML to parse it itself. The result was:

total coupon rows: 114
distinct codes: 114 | codes appearing >1: 0
same code -> DIFFERENT meal: 0
rows with price >= original_price (violates Zod): 0 []
expiry column present?: False

There were 114 records, not 190. Duplicate codes were 0. Price violations were 0. The expiration date column did not exist at all. That list from WebFetch was entirely fabricated. Claude even translated the Chinese item names into English in bulk (原味蛋撻 → original egg tarts), and the item name was the key for the upcoming cost-performance regression—meaning the key was destroyed and rebuilt before the work even began.

Claude wrote this lesson into its memory: a scraper must parse raw HTML; letting a model summarize it first is equivalent to writing hallucinations into the database.

Reporting 190 records, preparing to alter the schema, turning back to use curl, overturning the initial findings, and writing into memory—Claude completed this entire loop on its own. I never intervened throughout the entire process.

Two Sides of the Same Story

I later thought about this incident repeatedly and realized it has two sides worth discussing separately.

On one side, the model’s self-correction capability is already quite impressive. Claude did not blindly accept its own WebFetch output; it turned back, re-verified with curl, and overturned its own conclusion. This action is not a given—many tools just give you what they have and will never double-check themselves. This point alone is worth commending.

On the other side, the way AI perceives the external world still has undeniable shortcomings. The mistake it initially made—taking a hallucinated list as truth and even “discovering” evidence within it that coincidentally corroborated project rules—would simply never happen to a human.

If you asked me why a human would not make this mistake, I actually could not say for sure. Because for a human, it is just a matter of “taking a look”—opening the webpage, scrolling a bit, and matching the numbers. No one would ever need to be told, “This list might be fabricated”; one glance is enough to tell if it is real. But this “taking a look” is a hurdle that the model still struggles to overcome.

Perceiving, receiving, and analyzing information—these actions ultimately have significant differences between humans and models.

The Same Difference, Appearing Again in Reverse

There was another incident in the same project that highlighted this difference very clearly. In the HTML of all three source sites, the coupon expiration dates were nowhere to be found—because the expiration dates were printed on the coupon images. Claude scoured the HTML three times: using a loose date regex, looking for the nearest heading of each table, and performing an exact search for the word “expiration.” All attempts returned empty-handed because this information simply could not be inferred from the HTML structure.

In the end, I pointed it out in a single sentence: “On the site I frequent, the expiration dates are on the images.”

This information was something AI could never see from the HTML no matter what; a human, however, would know it just by taking a look.

Seeing the Boundaries Clearly to Know How to Divide the Work

This is also where I feel many people fail to use AI effectively. When faced with an entity that has a gap in perception yet is undeniably capable of self-correction, reactions often swing to two extremes: either deifying AI and believing it is omnipotent, or belittling AI and feeling that I might as well do it myself.

Both extremes are a waste. What is truly needed is to figure out where the respective capability boundaries lie—which tasks are a human specialty of “taking a look” and should be handled by humans, and which tasks involving combing through massive amounts of data are the AI’s specialty and should be delegated. Assigning the right task to the right party is the only way to maximize results.

When Claude caught its own fabricated numbers that day, it was a demonstration of the “self-correction” side of its capability boundary. When it initially fabricated that list, it was a demonstration of the “perception of the external world” side of that same boundary. Only by seeing both sides clearly will I know next time: what should be delegated to the AI, and what I should just take a look at myself.