You ask Cursor or Claude Code to integrate a library. The generated code looks plausible, compiles in your head, even passes lint — and then explodes at runtime with TypeError: client.queryRecords is not a function, or TypeScript yells Argument of type 'string' is not assignable to parameter of type 'QueryOptions'. The method does not exist. The option key is misspelled. The argument order is swapped. The AI fused the shape of three similar libraries and hallucinated a fourth one that feels right but is not real. This is a near-universal failure mode and it has nothing to do with model quality alone — it is about context grounding.
Common causes
Ordered by frequency in real coding sessions.
1. Library version drift between training data and your installed version
The AI learned a v2 API. You have v4 installed. Methods got renamed, options moved into a config object, callbacks turned into promises. The signature the AI emits was correct two years ago.
How to spot it: Check package.json for the version, then check the library’s CHANGELOG or releases page for breaking changes between that version and the AI’s likely training cutoff.
2. Method-name fusion across similar libraries
fetch, axios, got, undici, ky all do HTTP. The AI mashes their APIs. You get axios.fetch(url, { json: true }) — looks reasonable, is nonsense.
How to spot it: The method name appears in NO docs for the library you imported, but appears in a competitor’s docs.
3. Option-key hallucination
Real method, real arguments, but an option key like timeoutMs when the library actually accepts timeout. TypeScript catches some; loose-typed JS swallows it silently and the option is just ignored.
How to spot it: Object.keys(options) at runtime shows your key was passed; runtime behavior shows the default is still being used.
4. Return-type fabrication
const { data, error } = await client.query(...) — but the library actually returns Promise<QueryResult> where data is named rows and there is no error field (errors throw). The AI assumed a Supabase-style return shape.
How to spot it: console.log(JSON.stringify(result)) shows totally different keys than what was destructured.
5. Argument-order swap
fs.writeFile(content, path) instead of fs.writeFile(path, content). Or localStorage.setItem(value, key). AI memorizes the function name but not the parameter order from a sample it half-saw.
How to spot it: Files get created with garbled names containing the content. Or storage stores keys under values.
6. Made-up convenience method that should exist but does not
array.removeAt(index), string.contains(sub), date.addDays(7). These read like good API design — and several languages do have them — but the JS standard library does not. The AI was generous on your behalf.
How to spot it: MDN/docs search returns zero results for the method on that prototype.
Before you start
- Lock the exact version:
npm ls <package>orcat package.json | grep <package>. - Open the library’s docs page for that specific version, not “latest”.
- If using TypeScript, ensure
strict: trueso the type-checker flags signature mismatches up-front. - Save the AI’s original suggestion before fixing it — useful for a prompt patch later.
Information to collect
- The exact method call as the AI wrote it, copy-pasted.
- The installed package version (from
package.jsonandnode_modules/<pkg>/package.json). - The error message and stack trace, or the wrong runtime output.
- The library’s actual signature from its
.d.tsfile:cat node_modules/<pkg>/dist/index.d.ts | grep -A 3 <method>. - Whether the AI cited a source. If it cited a blog post, that blog is often the source of the hallucinated shape.
Step-by-step fix
Ordered from quickest sanity check to durable prevention.
Step 1: Confirm the method exists at all
grep -r "methodName" node_modules/<package>/dist/
Or in a Node REPL:
node -e "console.log(Object.keys(require('<package>')))"
If the method is not in the package’s actual exports, the AI hallucinated it. No amount of arg-fiddling will fix that — you need a different method or a different approach.
Step 2: Read the real signature from the type definitions
For typed libraries:
cat node_modules/<package>/dist/index.d.ts | grep -B 1 -A 10 "<method>"
This gives you the ground truth. Compare to what the AI wrote. The diff is the bug.
Step 3: Feed the real signature back to the AI
Re-prompt with the actual .d.ts snippet pasted in:
The real signature is:
query(sql: string, params?: unknown[]): Promise<{ rows: Row[]; rowCount: number }>
Rewrite the previous code to match this exact signature.
Do NOT add option keys not in this signature.
This grounds the next attempt in real source instead of training-set memory.
Step 4: Pin the AI to the installed version
In your system prompt or rules file:
We use <package>@<exact-version>. Treat any other version's API as wrong.
When generating code that uses <package>, first cite the method signature
from node_modules/<package>/dist/index.d.ts before writing the call site.
For Cursor: add a .cursorrules entry. For Claude Code: put it in CLAUDE.md at repo root.
Step 5: Add a runtime assertion at the call site
Even after fixing it, defensively guard against re-introduction:
if (typeof client.query !== "function") {
throw new Error(
"client.query missing — likely an AI-hallucinated method. " +
"Check the @yourorg/db version and re-read the .d.ts."
);
}
This turns a future regression into an immediate, named failure.
Step 6: Add a lint rule for known-hallucinated patterns
If your team keeps seeing the same fake method, add a custom ESLint no-restricted-syntax:
{
"rules": {
"no-restricted-syntax": ["error", {
"selector": "CallExpression[callee.property.name='queryRecords']",
"message": "queryRecords does not exist on this client. Use query()."
}]
}
}
The lint error fires the moment an AI suggestion lands.
Verify
- The replacement call compiles with
strict: trueand no// @ts-ignorepatches. - A unit test exercises the call path and the response shape is what your code expects (no surprise
undefinedfrom a misnamed key). grep -r "<hallucinated-method>" src/returns no hits anywhere in the codebase.- A repeat prompt for the same feature now generates the correct signature on the first try.
Long-term prevention
- Keep a
CLAUDE.mdor.cursorrulessection listing installed package versions and a “always check .d.ts before writing call sites” instruction. - Prefer typed libraries in TS projects; the type-checker catches most signature hallucinations before runtime.
- For untyped or loosely-typed libraries (raw HTTP SDKs, older npm packages), wrap them in a thin internal client with strict types. The AI then targets your wrapper, not the wild API.
- When integrating a new library, paste its README or
index.d.tsinto the prompt rather than letting the AI lean on training-set memory. - For long-running projects, regenerate type stubs whenever you upgrade a dependency so the AI sees current shapes.
- Code-review checklist: “Does this method exist in the actual library version?” as a literal step before approving AI-generated integrations.
Common pitfalls
- Trusting the AI’s “it works in v2” explanation — verify v2 actually had that method by checking the v2 docs/CHANGELOG.
- Suppressing the TypeScript error with
as anyinstead of fixing the signature. The runtime error will land later, in production. - Asking the AI to “fix it” without giving it the real signature — it will hallucinate a different wrong shape.
- Updating the library version to match the AI’s hallucination (“maybe it exists in v6?”) — usually it does not exist in any version.
- Assuming the AI hallucinated only one method — when one signature is wrong, the surrounding 30 lines often have additional fabricated calls.
For related failure modes see AI suggests a stale dependency, AI-generated TypeScript errors, and Cursor missed your project context.
FAQ
Q: The method does not exist but the AI is sure it does. Why?
The model averaged across many similar libraries during training. It is reproducing a plausible shape, not retrieving from a verified index. Treat all AI-generated API calls as hypotheses until you confirm against the actual .d.ts or docs.
Q: I pasted the docs into the prompt and it still hallucinated. Why?
Either the docs got truncated in context, or the AI weighed its training memory more than your pasted content. Re-prompt with “Use ONLY the signature in the block above. If the method I asked for is not there, say so explicitly.”
Q: Should I switch to a different library that the AI clearly knows better?
Not unless that library is genuinely better for your needs. The fix is grounding, not capitulating. Once you pin the real signature in your rules file, the AI handles the original library fine.
Q: How do I know if my whole AI-generated file has more hidden hallucinations?
Run TypeScript in strict mode and your test suite, both with full coverage. If both pass and runtime behavior matches the spec, you are clean. Type-check + tests catch ~90% of signature hallucinations.
Tags: #Troubleshooting #AI coding #Hallucination #api #type-errors