Dit artikel is nog niet vertaald naar het Nederlands — je leest het origineel in het English. Ook beschikbaar in:Deutsch, English, Українська
Phone Numbers That Are Too Regular
We have written before about fake phone numbers that cannot exist — numbers whose central office code began with a digit the numbering plan forbids, roughly one in eight of everything the generator had ever produced for North America. That article is about individual numbers failing individual rules.
This one is its mirror image, and it is the harder defect to see, because every number involved is correct.
Take a corpus of generated Finnish mobile numbers. Check each one: valid country code, valid mobile prefix, no forbidden digits, right shape, would be accepted by any form on the internet. Now count the digits. Every single number has exactly nine. Real Finnish mobile numbers have eight, nine or ten.
Nothing is wrong with any number. Everything is wrong with the set.
Where variable length is real
The assumption that a country has a mobile number length is very nearly true, which is what makes it dangerous. It holds for the overwhelming majority of numbering plans, and then it does not hold in a handful of places, and the exceptions are not obscure.
Finland. The national mobile number runs 8 to 10 digits including the two-digit prefix — the subscriber part is 6 to 8 digits, per the Finnish regulator's numbering regulation (Traficom M32). All three lengths are current, all three are in use, and the plan does not designate one of them as normal.
New Zealand. Length depends on which prefix you drew. The 21 range — the oldest mobile allocation — carries subscriber parts of 6 to 8 digits, giving national numbers of 8, 9 or 10. The other mobile prefixes carry 7 to 8, giving 9 or 10. There is no single answer even within the country, and the answer is a function of a value you have already chosen by the time you need it.
Serbia. Two-digit prefix plus a subscriber part of 6 or 7 digits: national numbers of 8 or 9.
And a counter-example that is at least as useful, because it is the same mistake pointing the other way. Swedish mobile numbers are frequently described as variable-length. They are not: the regulator's table gives maximum equal to minimum equal to nine digits for every mobile prefix. The variability people are remembering belongs to Swedish geographic numbers, which genuinely run 7 to 9. The companion article covers that check in detail; the point worth carrying here is that "variable length" and "fixed length" are both claims that get repeated without a source, and the myth exists in both directions.
What we were shipping
Our own numbering table holds 65 locale entries. Until recently, every one of them described length as a single integer: country code, list of mobile prefixes, length. One number.
That schema is not a bug in the ordinary sense. It is a factual assertion about the world, encoded as a type: the national number length is a function of the country alone. For 60 of the 65 entries the assertion happens to be true. For the other five — Finland, New Zealand, and Serbia in three script variants — it is false, and the code could not express the truth even if somebody had known it.
So the compromise was made, and it was made deliberately and written down: pick the most common length and use it everywhere. Finland, Serbia and New Zealand were all rounded to nine.
Consider what that produced. Nine digits is a legal Finnish mobile length. It is a legal Serbian one. It is a legal New Zealand one. Every individual number was valid. And the corpus was still impossible, because no real population of Finnish mobile numbers has a length histogram with a single bar in it.
This is the general shape and it is worth stating on its own:
Individual validity does not imply collective plausibility. A validator checks one record against the rules. Nothing in that process can notice that the thousand records around it are all identical along a dimension where reality varies.
It is also the reason this class of defect survives so long. The companion article's defect announced itself the moment anybody pasted a number into a form. This one announces itself only when somebody draws a histogram, and nobody draws a histogram of a field they believe is constant.
The tells of over-regular synthetic data
Length is the easiest one to check, which is why it is the example. It is not the only one. If you generate anything that is supposed to pass for real, these are the dimensions along which synthetic data is characteristically too clean:
| Tell | What the generator does | What reality does |
|---|---|---|
| Constant field length | One length per country / type | Several permitted lengths, coexisting |
| Uniform prefix selection | Every prefix drawn with equal probability | Market share is wildly unequal; one carrier may hold 40% |
| Uniform subscriber part | All 10^n tails equally likely | Allocation is blockwise and sparse; large ranges are unassigned |
| No collisions, ever | Deduplicated by construction | Real datasets contain duplicates, re-issued numbers, typos |
| All check digits valid | Computed correctly every time | Transcribed real data contains a small fraction of invalid ones |
| Perfectly uniform dates | Birthdays spread evenly over the year | Real births cluster by month, weekday, and around date defaults |
| Every field independent | Each drawn from its own distribution | City correlates with area code, surname with region, name with age |
| Exactly one format | Canonical form everywhere | Real records mix separators, cases, and legacy formats |
Only some of these are worth fixing, and which ones depend entirely on what the data is for. Perfect uniformity of the subscriber part is invisible to a human and expensive to fix properly, because it needs per-country allocation data that changes monthly. A single-valued length histogram is visible to anybody who runs one command and cheap to fix. Judging that trade is the actual work; the list above is just the inventory you need before you can judge it.
There is also a limit worth naming: you cannot fix all of these, and trying makes things worse. Every correlation you add is a correlation you now have to maintain and justify. The goal is not "indistinguishable from real data" — that is an arms race with no end and, for a generator of invented people, a slightly disturbing objective. The goal is "no single-command test finds a structure that is obviously synthetic."
The fix, and the trap inside it
The repair is a schema change: let the length field carry three shapes instead of one.
length := integer // fixed
| list of integers // uniform choice within the permitted set
| map { prefix -> integer|list, "*" -> integer|list }
Sixty of the sixty-five entries stay as a bare integer and are untouched, bit for bit. Four become lists. One becomes a map.
Now the trap, which is the part worth the article. The obvious middle option — "collect every length the country permits, pick uniformly from that set" — is wrong for New Zealand, and wrong in exactly the way the companion article is about.
New Zealand permits 8, 9 and 10 digits. But 8 digits are permitted only on the 21 range. A uniform draw from {8, 9, 10} applied to every prefix produces eight-digit numbers on 22, 27, 28 and 29, which the numbering plan does not contain. You would have started with numbers that were all the same length and correct, and ended with numbers that are varied and invalid — reintroducing precisely the defect that the other article spent 12% of a locale's output on.
Hence the map form, and hence the one implementation detail that actually matters:
Resolve the length after choosing the prefix, not before.
If the length is decided first, the prefix is constrained by it, and you have the dependency backwards. If the prefix is decided first, the length is a lookup. It is a one-line reordering and it is the difference between a correct model and a plausible-looking one.
The same trap generalises to any field whose validity constraints are conditional: postcode format given the region, tax-ID length given the entity type, IBAN length given the country, plate format given the vehicle class. Whenever a field's permitted values depend on another field, the dependent field must be resolved second, and a schema that stores the constraint as a flat set rather than a mapping cannot express the dependency at all. It will look like it works, because the flat set is a correct union — it is just not a correct union per case.
Uniform over lengths is not uniform over numbers
Here is the part where honesty costs something, and it is the reason we did not simply declare victory.
Regulators publish which lengths are permitted. They do not publish how many numbers of each length are in use. That is not an oversight; usage statistics are commercial data held by operators, and the numbering plan is a legal instrument about allocation. So "which lengths exist" is sourced and "how often each occurs" is not.
Faced with that, we pick uniformly within the correct set — right about the support, unverified about the shape, and stated as such in the code rather than quietly assumed.
But notice how large the unverified part is. Uniform over lengths is very far from uniform over numbers, because each extra digit multiplies the available space by ten:
| Locale | 8-digit space | 9-digit space | 10-digit space | Total |
|---|---|---|---|---|
| Finland | 7,200,000 | 72,000,000 | 720,000,000 | 799,200,000 |
| Serbia | 8,100,000 | 81,000,000 | — | 89,100,000 |
| New Zealand | 900,000 | 54,000,000 | 540,000,000 | 594,900,000 |
For Finland, a uniform choice among the three lengths sends one number in three into a pool that is 0.9% of the total space. Drawing uniformly over the space instead would give 0.9% / 9.0% / 90.1%. The two policies differ by a factor of 36 in the eight-digit band. Neither is known to be right. What is knowable is that they are wildly different, and that picking one without noticing the difference is not a decision, it is an accident.
Measured on the generated corpus, our current choice produces:
| Locale | 8 digits | 9 digits | 10 digits |
|---|---|---|---|
| Finland | 33.0% | 33.3% | 33.7% |
| Serbia | 49.8% | 50.2% | — |
| New Zealand | 5.7% | 47.5% | 46.8% |
New Zealand's 5.7% is the interesting row. It was not chosen. It falls out of the map: only one of six prefixes may be eight digits, so eight-digit numbers appear at roughly one sixth of one third. Getting the constraint right produced a non-uniform length distribution as a side effect — which is a small illustration of a general principle, that modelling the structure correctly buys you realism you did not have to estimate. Wherever you can replace a guessed distribution with a hard constraint, do it; the constraint is defensible and the guess is not.
The cost nobody expects: variable length means variable randomness
One practical note, because it is the reason this compromise existed in the first place rather than being fixed years ago.
If your generator derives an entire record from a single deterministic stream — same input, same record, forever — then the stream is positional. Field n consumes whatever the stream produces at position n. A field whose number of draws depends on the values drawn shifts everything after it.
A variable-length phone number does exactly that: choosing a length costs a draw, and then the number of digit draws depends on the length chosen. Do it naively and every record containing a Finnish phone number changes, including all the fields that have nothing to do with phones.
The resolution has two halves and both are worth copying:
Spend the draw only where the variability is real. A scalar length resolves with zero draws. Sixty of sixty-five locales are therefore untouched — not "close enough", but verifiably identical: the same numbers from the same seeds, and the stream sitting at the same position afterwards. A change that could have perturbed everything perturbs five entries.
Confine the variability behind a boundary that restores the stream. Where a field genuinely needs a data-dependent number of draws, it belongs behind a call that saves and restores the stream position, so its cost is invisible from outside. That is the same invariant the companion article had to protect when it rejected rejection-sampling as a fix for invalid North American codes, and it is worth reading that argument before designing around it: Fake Phone Numbers That Cannot Exist.
The general lesson is that determinism is not free and it is not local. It is a constraint on the shape of every generator function in the system, and it quietly vetoes a large class of otherwise-obvious implementations. The reason Finland was rounded to nine digits for years was not ignorance about Finland. It was that the honest version looked like it would cost the determinism guarantee, and nobody had measured whether it actually would. It did not: the cost was five entries, and it was only ever going to be five entries.
Measure the blast radius before you accept a compromise on its behalf. That is the most transferable sentence in this article.
How to audit your own generated corpus
All of this is checkable in a few minutes against data you already have.
1. Histogram every length field. Not the mean, not the mode — the full histogram. A single bar where the specification permits several is the whole defect, visible instantly.
2. Check the permitted set against a primary source, in both directions. Are you emitting a length that is not permitted? Are you failing to emit one that is? The second question is the one nobody asks, and it is the one that finds this bug.
3. Do it per prefix, not globally. A globally correct length histogram can be locally impossible. New Zealand's global set {8, 9, 10} is right; applied to prefix 27 it is wrong. Any conditional constraint has to be audited at the level the condition lives at.
4. Compare the shape of your distribution, not just its support. Getting the set of permitted values right is the first 80%. Whether you are uniform over values or uniform over the space they represent is a factor-of-36 question in at least one real case.
5. Write down what is sourced and what is assumed, inside the artefact. "These lengths come from the regulator; the proportions between them are an assumption, because usage statistics are not published" is one sentence. Without it, a future reader cannot tell a measured distribution from a placeholder, and will either trust it too much or redo the work.
6. Look for other constants that should not be constants. The single-integer length field was not a mistake anybody made; it was an assumption nobody articulated. Every scalar in a specification table is a claim that the quantity does not vary. Some of those claims are false and none of them are labelled.
The checklist
- A field that is always the same value is a hypothesis, not a fact. Check the hypothesis against a primary source before shipping the schema that encodes it.
- Individual validity does not imply collective plausibility. Every number can pass every rule while the corpus remains impossible.
- Histogram the fields you believe are constant. They are the ones nobody has ever plotted.
- When a constraint is conditional, resolve the condition first. Prefix before length, region before postcode format, entity type before identifier length.
- Do not fix over-regularity by adding uniform variation. Uniform over the union of permitted values generates values that are permitted somewhere and invalid here. That is a worse defect than the one you started with.
- Distinguish the support from the shape. Regulators publish what is permitted; almost nobody publishes what is used. Say which of the two you have.
- Uniform over categories is not uniform over the space. For anything positional, each extra position multiplies the space by the base; a flat choice over lengths is an extremely non-flat choice over values.
- Prefer a hard constraint to an estimated distribution. Structure you can defend beats realism you had to guess, and it often produces the realism for free.
- Measure the blast radius of a compromise before accepting it. "This would change everything" was the reason a known-wrong value shipped for years. It would have changed five entries out of sixty-five.
- Keep the number of random draws independent of the values drawn, or hide the dependence behind a boundary. Determinism is a global constraint on local implementations.
The companion article ended on a question it could not answer: whether generating plausible phone numbers is a good idea at all, given that a plausible number in a small country is quite likely to belong to somebody. This article does not answer it either. What it adds is the other half of "plausible": a number can be individually indistinguishable from a real one and still sit in a corpus that no real population could produce. Both halves have to hold, and only one of them is something a validator can check for you.
For the structural rules, the reserved fiction ranges, and the determinism argument in full, see Fake Phone Numbers That Cannot Exist. For the same "the schema asserted something about the world" failure in a different field, see Postal Code Systems and Why There Is No Universal Generator. For a defect that was invisible because every aggregate metric agreed it was fine, see Half of Your Weighted List Is Not Weighted.
Data as of 2026-07-21
All figures were measured on 21 July 2026 against the shipped numbering table and the generated corpus. The length distributions were re-derived for this article by direct measurement of the generated files and by simulation over 10,000 numbers per locale, not quoted from the change record.
Sources and notes:
- Table composition — 65 locale entries. 60 carry a scalar length; 4 carry a list of permitted lengths (Finland, and Serbia in Cyrillic, Latin and default script variants); 1 carries a prefix-keyed map (New Zealand). The five variable entries represent three countries, since the three Serbian entries differ only in script and must be kept in step with each other.
- Finland — national mobile numbers of 8, 9 or 10 digits, from a two-digit prefix plus a 6-to-8-digit subscriber part, per Traficom regulation M32. Eight mobile prefixes are shipped. Generation space by length: 7,200,000 / 72,000,000 / 720,000,000, total 799,200,000.
- New Zealand — the
21range permits 8, 9 or 10 digits; the other five shipped mobile prefixes permit 9 or 10. Generation space by length: 900,000 / 54,000,000 / 540,000,000, total 594,900,000. The observed 5.7% share of eight-digit numbers is a consequence of the constraint, not a configured target. - Serbia — 8 or 9 digits, from a two-digit prefix plus a 6-or-7-digit subscriber part. Nine prefixes in the default entry, eight in each script variant. Generation space: 8,100,000 / 81,000,000.
- Sweden — mobile prefixes carry maximum equal to minimum equal to 9 digits, so the widely repeated claim of variable-length Swedish mobile numbers is false; Swedish geographic numbers do vary, at 7 to 9. Established during an earlier audit against the regulator's numbering table and reported in the companion article; not re-verified here.
- Measured length distribution — from the generated corpus on disk, counting digits after the country code. Finland: 6,597 / 6,656 / 6,743 of 19,996 numbers at 8 / 9 / 10 digits, i.e. 33.0% / 33.3% / 33.7%. Serbia: 9,952 / 10,044 of 19,996 at 8 / 9 digits, i.e. 49.8% / 50.2%. New Zealand: 1,138 / 9,499 / 9,362 of 19,999 at 8 / 9 / 10 digits, i.e. 5.7% / 47.5% / 46.8%. An independent simulation of 10,000 draws per locale reproduces these to within a few tenths of a percentage point.
- Generation-space figures — computed as, for each prefix,
9 × 10^(length − prefix digits − 1), summed over prefixes and lengths. The leading subscriber digit is constrained away from zero, which is where the factor of 9 comes from. - Proportions between lengths are not verified. The choice within a permitted set is uniform. Numbering plans state which lengths are allowed; they do not state how many numbers of each length have been issued, and operator-level allocation data was not available. This is recorded as an explicit assumption in the source rather than left implicit.
- Locales with a scalar length are unchanged — verified by generating from fixed seeds before and after the schema change and comparing both the emitted numbers and the position of the random stream afterwards; all four spot-checked locales produced identical output and an identical subsequent stream position. A scalar length consumes no draw, which is why the change is inert for 60 of 65 entries.
- The historical compromise — Finland, Serbia and New Zealand were previously fixed at 9 digits, recorded in the source as a deliberate limitation of the one-integer format rather than as a belief about those countries. Nine digits is a permitted length in all three, so no individual number generated under the old rule was invalid.