Verification Discipline: Catching and Correcting Hallucinations in AI Coding Agents
A Practical Framework By Jack Figliomeni · Saratoga Springs, NY · September 24, 2026 As software development shifts toward generating code from natural-language prompts, widely known as "vibe coding", the principal constraint on quality is no longer how quickly code can be produced, but how rigorously it is verified. Large language models (LLM) write code that is fluent and projects confidence, yet they routinely fabricate Application Programming Interfaces (API), invent dependencies (external library, framework or package the software is reliant on), misinterpret project context, and silently violate stated requirements. This paper argues that the ability to anticipate, detect, diagnose, and correct these failures, here coining Verification Discipline, is a distinct, learnable engineering capability. Drawing on recent pragmatic classifications of code hallucination, security research on Artificial Intelligence (AI)-suggested packages, and controlled productivity studies, it explains what code hallucinations are, why they emerge from the way models are trained, the conditions that make them most probable, and a practical, iterative framework for counterbalancing them. A companion diagram traces the causal pathway by which a hallucination forms. In early 2025, Andrej Karpathy popularized the term "vibe coding" for a style of development in which the programmer articulates intent in plain language and delegates implementation to an AI assistant, often accepting the result with minimal review [9]. The appeal is evident, scaffolding that once took hours now materializes in seconds. The hazard is less apparent. An LLM's output is optimized to be plausible, not correct, and in software the distance between the two can separate a working system from a latent defect, a security vulnerability, or a compromised dependency. Empirical evidence suggests developers consistently misjudge this distance. In a randomized controlled trial by Model Evaluation and Threat Research (METR), sixteen experienced open-source developers completed 246 real tasks in repositories (centralized storage locations for project files) they knew well. When AI tools were permitted, tasks took 19% longer yet the same developers had forecast a 24% speedup and, even afterward, believed they had been 20% faster [5]. The grey area between perceived and actual performance is precisely where unexamined AI output resides. The competency this paper describes, then, is not "using AI to write code," which is increasingly negligible, but governing AI-written code and understanding how, when, and why an agent is likely to trip up, recognizing a fabrication before it proliferates, and structuring the workflow so trip ups or errors are surfaced by evidence rather than discovered in production. In natural-language generation (prompting), a hallucination is output that is fluent but unfaithful to its source, reality or instruction [11]. In code, the definition becomes trepidatious, a hallucination is generated code that deviates from the user's intent, contradicts itself, or misrepresents real-world facts about languages, libraries, and environments [2]. Notably, hallucinated code frequently compiles and runs. Its defect lies in meaning, context, or fact rather than syntax, which is why it evades casual inspection. Ziyao Zhang et al. studied outputs from six mainstream LLMs on repository-level tasks and identified three major categories with eight subcategories [1]. Other work displays hallucinations by their visible symptoms, syntax, runtime, functional-correctness, and code-quality failures [3]. The table below combines both views into a working classification. | Category | Subtype | What it looks like in practice | Typical symptom | |---|---|---|---| | Task and requirement conflict | Functional violation | Solves an adjacent problem; ignores an edge case the prompt specified | Tests pass on the happy path, fail on boundaries | | Task-requirement conflict | Non-functional violation | Correct logic, but insecure, inefficient, or stylistically inconsistent - "losing the plot" | Code review or security scan flags | | Factual-knowledge conflict | API / library fabrication | Calls a method, parameter, or flag that does not exist or belongs to another version | AttributeError, undefined is not a function, type errors | | Factual-knowledge conflict | Package fabrication | Imports or installs a dependency that does not exist in the registry | Install failure-or silent success if the name was squatted | | Factual-knowledge conflict | Background-knowledge error | Misstates a protocol, algorithm, or domain rule | Logically wrong output that "looks right" | | Project-context conflict | Environment conflict | Assumes the wrong runtime, framework version, or OS | Works in the model's imagination, not in your build | | Project-context conflict | Dependency conflict | References user-defined functions, types, or modules that do not exist or have different signatures | Broken imports, mismatched interfaces | | Project-context conflict | Non-code resource conflict | Invents configuration keys, environment variables, file paths, or database columns | Runtime null/undefined, missing-resource errors | | Agentic / process | False completion claim | Reports a task as done, tests as passing, or a file as edited when it was not | Discrepancy between the agent's summary and the diff | The final row extends the published classifications to agentic tools, where the model not only writes code but also describes what it did. That self-report is generated text too, and it can be just as wrong. Understanding the underlying causes matters because each one implies a different countermeasure. Five are especially consequential; Figure 1 traces how they combine. Predicting the next token is not the same as checking facts. An LLM generates the most statistically likely continuation of its input. When a fact is well covered in training data, likely and true line up; when it is rare, recent, or private, the model still produces the most plausible-sounding answer. Adam Tauman Kalai et al. shows that if a model can't reliably tell true statements from false ones, hallucinations naturally result from prior training [6]. A reasonable-sounding method like client.fetchAllRecords() (calls all rows, data payloads or documents into memory) is exactly what this produces. Training rewards "confident" guessing. The same authors argue that hallucinations persist because most evaluations grade models like multiple-choice exams, a guess can earn points, while "I don't know" earns none [6]. Models learn to be good test-takers that bluff when unsure. For developers, the takeaway is simple, sounding fluent and confident proves nothing. Knowledge is frozen and mixes versions. Training data is a snapshot covering many library versions at once, so models blend old and current APIs or apply one framework's conventions to another. Zhang et al. identifies outdated or conflicting library knowledge as a recurring cause and find that retrieving accurate context meaningfully reduces errors [1]. Context is limited and unevenly used. An agent only sees what fits in its context window, and it doesn't pay equal attention to everything in it: Yang Liu et al. shows that models use information at the start and end of long inputs much better than information in the middle [7]. In a large repository, the agent fills gaps in its view of the codebase with guesses, this is what produces project-context conflicts. Going along with the user, then doubling down. Models trained on human feedback show "obsequiousness", tending to agree with how the user frames a problem even when that framing is wrong [8]. In multi-step agent work, an early mistake also tends to snowball once the model commits to a false premise, later reasoning justifies it instead of fixing it [12]. A leading prompt ("just use the X library for this") can plant a made-up detail that the agent then builds out across several files. Hallucinations are not uniformly distributed across tasks. Their likelihood rises predictably under identifiable conditions, which allows a developer to calibrate scrutiny rather than inspect everything with equal intensity. | Risk condition | Why risk rises | Heightened scrutiny target | |---|---|---| | Niche, new, or fast-moving libraries | Sparse or version-conflicted training data | Every imported symbol and method signature | | Adding dependencies | Package names are cheap to invent; 19.7% of LLM-recommended packages across 16 models did not exist [4] | Registry existence, publisher, age, download history | | Large or unfamiliar repositories | Relevant code falls outside or in the middle of the context window | Calls to internal functions, types, and config | | Long agentic sessions | Accumulated context dilutes early instructions; errors snowball (§3.5) | Drift from original requirements; repeated edits to the same file | | Vague or leading prompts | The model fills ambiguity with plausible defaults and defers to user framing | Unstated assumptions baked into the implementation | | Security-sensitive code | Insecure patterns are common in public code; Pearce et al. found roughly 40% of Copilot-generated programs in security-relevant scenarios were vulnerable [10] | Authentication, input handling, secrets, SQL, file paths | | Environment-specific glue | Build tooling, CI, deployment config, and OS commands vary widely | Commands and config keys against official docs | | Agent self-reports | Completion summaries are generated text, not observations [2] | The actual diff, test output, and logs | The package finding deserves special attention because it turns a correctness problem into a security problem. Joseph Spracklen et al. found that hallucinated package names repeat across prompts, which makes them predictable enough for attackers to register ahead of time as malware, a technique now called "slop squatting" [4]. Detection rests on one governi
Comments
No comments yet. Start the discussion.