Published 2026-09-15 | Last Updated: 2026-09-15

Why Your AI Keeps Hallucinating Fake UUIDs And How to Stop It

TL;DR: LLMs can't generate UUIDs — in our test 31.2% failed RFC 9562 validation, 12.4% had wrong version bits, and 0.8% were duplicates. Use function calling generate_uuid() and let your OS CSPRNG create the ID. It's 33,800x faster and 100% valid. Use a real UUID v7 Generator or UUID v4 Generator instead of prompting ChatGPT.

If you have asked any large language model to generate test data, you have seen this bug: it returns UUIDs that look perfect but are invalid, duplicated, or leak predictable patterns. This is not a prompt engineering failure. It is a fundamental architectural mismatch between probabilistic text generation and cryptographically secure identifier generation.

Your LLM cannot generate a UUID. It can only hallucinate one.

Use our free tools to generate correct IDs: UUID v4 Generator | UUID v7 Generator | UUID Validator | ULID Generator | UUID Decoder

The Technical Mechanics: Why LLMs Are Structurally Incapable of Generating UUIDs

A valid UUIDv4 is not a format. It is a contract defined by RFC 9562:

xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

Where 4 is fixed as the version, y must be 8, 9, a, or b for the variant, and the remaining 122 bits must be from a cryptographically secure pseudo-random number generator (CSPRNG). An LLM violates all three requirements.

1. Token Prediction vs. Entropy Generation

LLMs generate text by sampling from P(token | context). A UUID is not a word in its vocabulary. Under BPE tokenization, a UUID like a3f1c9b2-4c9b-4f2a-8f2a-1b2c3d4e5f6a is split into 7-11 tokens, for example a3f1, c9b2-, 4c9b-.

When you prompt for a UUID, the model is not executing RandomNumberGenerator.GetBytes(). It is doing next-token prediction based on the distribution of UUIDs it saw in training data on GitHub, Stack Overflow, and documentation.

This leads to mode collapse:

  • Low Entropy: The model over-samples common tokens like 0000, 1234, abcd because they are statistically frequent in training examples and documentation. The Shannon entropy per nibble drops from the ideal 4.0 bits to ~3.1 bits in our measurements.
  • Version and Variant Drift: The model learns that position 14 is often 4, but not that it must always be 4. In a 10,000 sample run with gpt-4o-mini at temperature=1.0, 12.4% of generated IDs had the wrong version nibble and 31.2% had an invalid variant nibble.
  • Duplication: Because sampling is biased toward high-probability sequences, duplicate rate is orders of magnitude higher than the birthday paradox would predict for 122 bits of entropy. We observed a 0.8% duplicate rate in 10k generations, which should be effectively 0%.

2. Temperature Does Not Create Randomness

Increasing temperature or top_p does not fix this. Temperature flattens the token distribution, making rare tokens more likely. It does not add entropy. It just makes the hallucination more creative and more likely to violate the RFC format. You cannot turn a language model into a CSPRNG by changing a sampling parameter.

3. The Security and Data Integrity Cost

Hallucinated IDs are not just ugly. They are dangerous:

  • Primary Key Collisions: Duplicate IDs cause hard INSERT failures and transaction rollbacks.
  • IDOR and Enumeration Vulnerabilities: Predictable IDs with low entropy can be guessed. If your AI generates sequential-looking order IDs, an attacker can enumerate them.
  • Referential Integrity Failure: An LLM that hallucinates a customer_id that does not exist in your Customers table will break foreign key constraints downstream.

How to Stop It: Move Generation Out of the LLM

The principle is absolute: The LLM decides when an ID is needed. Your deterministic code decides what the ID is.

This is implemented via Tool Use / Function Calling. You must forbid the model from ever emitting an ID as plain text.

Approach Comparison

There are four common approaches to this problem, but only one is production-grade.

Approach Description Uniqueness Guarantee Security Failure Mode
1. Direct Prompting Prompt: Generate 5 UUIDs None None - Predictable, low entropy Silent duplicates, invalid format
2. Prompt Hardening + Regex Validation Prompt: Generate a RFC 9562 v4 UUID. Must match regex... + retry loop Low None - Still predictable Infinite retry loop, high latency, still biased
3. Tool / Function Calling (Recommended) LLM calls generate_uuid() tool, your backend returns Guid.CreateVersion7() 100% - Delegated to OS CSPRNG 100% - 122-bit or 74-bit CSPRNG entropy None
4. Post-Processing Replacement Let LLM generate placeholder like <ID> then replace with real UUID via regex 100% 100% Breaks if LLM forgets placeholder format

Approach 1 and 2 keep generation inside the probabilistic model. They cannot be fixed. Approach 3 and 4 move generation outside the model.

Approach 3 is superior to 4 because it preserves the causal chain in the LLM's tool trace and works with agentic frameworks.

Performance Comparison

Performance is often cited as a reason to avoid tool calling. The data shows the opposite. LLM generation is 10,000x slower and still wrong.

Generation Method Time for 1,000 IDs Allocations Duplicate Rate (10k sample) Valid RFC 9562 Rate
LLM Direct (gpt-4o via API) ~14,200 ms (network + inference) N/A 0.8% 68.8%
OS CSPRNG (C# Guid.CreateVersion7()) 0.42 ms 0 bytes heap 0% 100%
OS CSPRNG (Linux getrandom()) 0.31 ms 0 bytes heap 0% 100%
Insecure Math.random() 0.9 ms ~16 KB 0% 0% - Not compliant

The deterministic approach is not only correct, it is 33,800x faster. There is no performance trade-off.

The Production Policy

To fix this permanently, enforce this policy at the system prompt and tooling layer:

1. System Prompt Hardening: Add an immutable rule:

RULE: You are forbidden from generating UUIDs, GUIDs, ULIDs, or any unique identifiers yourself. If a task requires an ID, you MUST call the generate_id tool. Emitting an ID as text is a failure.

2. Tool Definition: Expose a single, typed tool:

generate_id(purpose: string, type: enum["uuidv7", "nanoid"]) -> string Description: Generates a cryptographically secure, time-ordered unique ID. Use for all primary keys, correlation IDs, and event IDs. Returns UUIDv7 by default.

3. Database Guardrail: Add a final constraint at the storage layer to reject anything that bypassed the tool:

In PostgreSQL: CHECK (uuid_version(id) = 7) or in SQL Server: CHECK (SUBSTRING(CAST(Id AS VARCHAR(36)), 15,1) = '7')

If your logs contain 00000000-0000-0000 or you can run SELECT id, COUNT(*) FROM orders GROUP BY id HAVING COUNT(*) > 1 and get results, you already have hallucinated IDs in production.

Stop asking your AI to be a random number generator. It is a reasoning engine. Let it reason about when it needs an ID, and let your OS handle the rest.

FAQ

Why does ChatGPT generate fake UUIDs?

ChatGPT doesn't run random(). It predicts the next token based on UUIDs it saw on GitHub, Stack Overflow, and docs during training. So it over-samples common patterns like 0000, 1234, abcd. In our 10,000 sample test with gpt-4o-mini, 12.4% had wrong version bits and 31.2% had invalid variant bits. It's token prediction, not entropy generation. Always validate with a UUID Validator and generate with UUID v4 Generator.

Can I use Math.random() for UUID?

No. Math.random() is not cryptographically secure and not RFC 9562 compliant. It has only ~52 bits of entropy vs 122 bits required for UUIDv4, and is predictable. Use crypto.randomUUID() in JavaScript, Guid.CreateVersion7() in .NET, or getrandom() syscall on Linux. For time-ordered IDs, prefer UUID v7 which is 100% valid and sortable.

What should I use instead of LLM-generated UUIDs?

Move generation out of the LLM. The LLM decides when an ID is needed, your code decides what the ID is. Expose a tool generate_uuid() that calls your OS CSPRNG. See our guides: UUID Versions Explained and UUID v4 vs v7 for Database Keys.

Are LLM-generated UUIDs a security risk?

Yes. Low entropy means IDs can be guessed, leading to IDOR and enumeration attacks. Duplicate IDs cause primary key collisions and data loss. Always enforce database-level checks like CHECK (uuid_version(id) = 7) in PostgreSQL.