Verify Without Judging: Deterministic and Generative Approaches to Code Hallucination Detection

Summary

Detecting hallucinations in AI-generated code currently admits two major families of approaches: those that verify against an external source of truth (deterministic) and those that infer the probability of error through models (generative). This article reviews both based on recent literature and experiences published on DEV Community, and situates the specific case of verifying Python packages and APIs against PyPI. The provisional conclusion is that neither family fully covers the problem: deterministic approaches offer objective evidence but limited scope; generative approaches expand coverage but introduce uncertainty. The choice depends on the type of error you want to catch and the cost you are willing to bear.


1. The Problem: Three Failures with the Same Name

Saurav Bhattacharya argues in a recent article that hallucination detection is an instrumentation problem, not a model quality problem. His central argument is that in agent systems, the word “hallucination” groups at least three distinct failures:

  • Parametric leakage: the agent responds from its training memory instead of using the result of the tool provided to it. The response may be correct, but it is correct by chance, not because it is grounded.

  • Fabricated grounding: the agent cites a source, an identifier, or a number that does not appear in the retrieved context. This is the most dangerous case because it has the appearance of a documented claim.

  • Unsupported synthesis: each individual fact is in the context, but the conclusion the agent draws does not follow from the source.

The practical implication is that these three failures require distinct detectors. A single “hallucination score” that mixes them produces a figure that no one can interpret.


2. The Critique of Generative Methods

The same article points out a known weakness of model-based detectors: self-consistency (sampling multiple times and checking if answers match) detects unstable hallucinations, but fails with stable ones. If an agent systematically reproduces the same erroneous datum from its parametric memory, the samples match and the detector reports high confidence. The model is reproducibly incorrect, and consistency was the signal.

Academic literature supports this caution. A study on static analysis methods for library hallucinations notes that type inference tools, such as Pyright, are more reliable than LLM judgment in detecting import and type errors. The same work acknowledges, however, that static analysis has limits: data flow and control flow operations are the most promising avenues for expanding its coverage, but types can mutate during execution and escape detection.


3. The Deterministic Proposal: Verify Against the Source

The alternative that Bhattacharya defends is mechanical and explainable: extract verifiable claims from the output and check them against the text that the agent actually retrieved. The requirement is to preserve that text (the execution trace); without it, any verification is a guess.

In the code domain, this idea has materialized in several forms. The libhallubench tool evaluates LLM code generation against a benchmark of non-existent libraries, using the PyPI package list as a source of truth. The vibe-check project detects typical patterns of AI-generated code, including invented imports, through pattern matching, without resorting to models or cloud services. An article from the same community describes how ESLint and TypeScript fail to detect an invented import because the linter validates syntax, not the existence of the package in the registry, and the type compiler only checks types if type definitions exist, which cannot be installed for a package that does not exist.

In this landscape, verifying Python packages and APIs against the actual wheel on PyPI sits in the deterministic tradition: it does not infer, it checks membership in a set. The advantage is that it does not require installing the package or running the analyzed code; the limitation is that it only covers the existence of symbols, not the correctness of their use.


4. The Generative Proposal: Detect Spans with Trained Models

The generative family has advanced notably. LettuceDetect v2 is a detector trained on a unified benchmark of 74,285 examples labeled at span level, spanning code, tool outputs, and documents. The generative model (Qwen 3.5-2B) returns hallucinated spans as structured JSON, typed by category (contradiction, unsupported addition, fabricated reference) and subcategory (entity, temporal, numeric, identifier, attribute). On the unified test set, it achieves 0.689 span-F1; on code agent responses, 0.602.

The advantage of this approach is coverage: it detects errors that an existence verifier cannot catch, such as an incorrect logical condition or a wrong numeric value. The limitation is inherent to any probabilistic model: it does not offer a deterministic explanation and its performance varies by domain and grounding source.


5. The Gap That Neither Covers: Logic and Resources

The CodeHalu taxonomy, cited in the documentation of the project in question, distinguishes four categories: nomenclature, mapping, resources, and logic. Deterministic verifiers against registries reasonably cover the first two. The latter two fall outside their scope by definition: they require analyzing data flow, conditions, or algorithmic complexity, not merely the existence of a symbol.

Literature confirms this limit. An analysis of structural failures in generated code concludes that most of them escape type checking, tests, and static security analysis. Another work describes the case of a discount function whose types are correct but whose semantics are wrong because the percentage unit does not match the one used by the rest of the code: the compiler cannot detect it because the types check out.

Generative detectors like LettuceDetect v2 attempt to cover part of that gap, but do not offer deterministic guarantees. The gap between “the symbol exists” and “the code does what it should” remains, in large measure, an open problem.


6. Considerations for Detector Design

From the above, some provisional observations can be drawn:

Deterministic verification is cheap and explainable. Checking the existence of a package or function against a registry does not require executing user code or installing dependencies. The cost is bounded and the result is membership in a set, not a probability.

Deterministic coverage is necessarily partial. It is limited to errors that can be expressed as a membership check or signature check. Logic errors, data flow errors, or complexity errors fall outside.

Generative methods expand coverage but introduce uncertainty. Their performance depends on the training benchmark and they do not offer a deterministic explanation of the failure.

Combination is plausible. A deterministic detector for symbol existence and a generative or semantic detector for logic could cover complementary layers. The open question is how to integrate them without the uncertainty of the second contaminating the reliability of the first.


7. Limitations of This Analysis

This text is based on a non-systematic review of literature and community articles. No comparative empirical evaluation of the described approaches has been performed. The figures cited come from the original works and have not been replicated in the specific context of Python package verification. The CodeHalu taxonomy has been used as a descriptive framework, not as a benchmark validated in this analysis.


References

  1. Bhattacharya, S. (2026). Hallucination Is Not a Vibe: How to Actually Detect Ungrounded Claims in Agent Output. DEV Community.

  2. libhallubench (2026). PyPI.

  3. 5 Code Smells Only AI Creates (And How to Detect Them). DEV Community.

  4. ESLint can’t catch this: 5 failure modes unique to AI-generated code. DEV Community.

  5. LettuceDetect v2 in Semantic Router: Generative Hallucination Detection as a vLLM Endpoint. GitHub.

  6. KRLabsOrg. LettuceDetect. GitHub.

  7. The verification gap in agent-written code: what actually breaks. GitHub.

  8. The Patchwork Problem in LLM-Generated Code. arXiv.

  9. For mitigation, we use three metrics. OpenReview.