You ask Cursor, Claude Code, or Codex 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.
Fastest fix: open the library’s real type definitions (node_modules/<package>/dist/index.d.ts) or run node -e "console.log(Object.keys(require('<package>')))", paste the actual signature back into the chat, and tell the model to rewrite the call using only that signature. That single grounding step fixes the current call. The rest of this page makes the fix stick across the whole file and prevents the next one.
This is a near-universal failure mode and it is not purely a model-quality problem. Even the strongest June 2026 models (GPT-5.5, Claude Opus 4.7, Gemini 3.1 Pro) hallucinate signatures when they are forced to lean on training memory instead of your installed source. It is about context grounding, and grounding is something you control.
Which bucket are you in
Match your symptom to the cause, then jump to the matching section below.
| What you see | Most likely cause |
|---|---|
X is not a function / method missing at runtime | Made-up method (cause 2 or 6) or version drift (cause 1) |
| Method runs, but an option is silently ignored | Option-key hallucination (cause 3) |
Destructured fields are undefined | Return-type fabrication (cause 4) |
| Wrong data lands in the wrong place (file named after its content, etc.) | Argument-order swap (cause 5) |
TS error ... is not assignable to parameter of type ... | Wrong arg type, often version drift (cause 1) or fused API (cause 2) |
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
Add a rule so the model checks real source before writing any call:
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.
Where to put it, as of June 2026:
- Cursor: create a project rule at
.cursor/rules/<name>.mdc(the single-file.cursorrulesformat is deprecated and is silently ignored in Agent mode, so a.cursorrulesrule will quietly do nothing in agentic chats). The.mdcfile takes frontmatter:description(so the agent knows when to apply it),globs(e.g.**/*.tsto scope it), andalwaysApply: trueif it should load every session. - Claude Code: put it in
CLAUDE.mdat the repo root. It is read at the start of every session. Keep it short; it shares the context budget with your code. - Codex / other agents: use their equivalent project-instructions file (
AGENTS.mdor the tool’s system-prompt/rules setting).
Step 4b: Feed live docs with an MCP docs server (the durable grounding fix)
The root cause is stale training memory. The most-adopted 2026 fix is to give the agent a live documentation source instead of relying on memory. Context7 is an MCP server that fetches current, version-specific docs for thousands of popular libraries and injects them into context on demand via its get-library-docs tool. Once it is configured in Cursor or Claude Code, prompt with “use context7” (or let the agent call it) and the model writes against today’s real API rather than a two-year-old shape.
This complements the rules file: the rule tells the agent to check source, the MCP server gives it the source to check.
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.
How to confirm it is fixed
- 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.md(or a.cursor/rules/*.mdcproject rule) listing installed package versions and an “always check.d.tsbefore writing call sites” instruction. Do not rely on the legacy.cursorrulesfile for agentic work. - Wire up a live-docs MCP server (Context7 or equivalent) so the agent pulls version-specific docs on demand instead of guessing from memory.
- 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.
External references: Cursor Rules docs (current .mdc rule format) and Context7 MCP server (live, version-specific library docs for agents).
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: Is there a setup that stops this from happening at all?
The closest thing is a live-docs MCP server such as Context7. It injects current, version-specific documentation into the agent’s context so the model writes against the real API instead of training memory. Pair it with a rules-file instruction to “check source before writing the call,” and most signature hallucinations stop appearing in the first draft. It is not a 100% guarantee, so keep strict mode and tests on.
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 plus tests catch the large majority of signature hallucinations; the rest are usually loosely-typed option keys, which the runtime assertion in Step 5 and a quick console.log(JSON.stringify(result)) will surface.
Tags: #Troubleshooting #AI coding #Hallucination #api #type-errors