Developers

E.164 regex: why a pattern is not enough to validate phone numbers

The common E.164 regex accepts impossible numbers. Real counterexamples, the shortest valid international numbers, and what to use a regex for instead.

By Published 7 min read

On this page

The common E.164 regex, ^\+[1-9]\d{1,14}$, only checks shape: a plus, a non-zero first digit, at most 15 digits. It accepts country codes that don't exist, area codes no country uses, and numbers of the wrong length. To validate a phone number, use a numbering-plan library such as libphonenumber. Keep the regex for one job: checking that stored values are already normalized.

What does the standard E.164 regex actually check?

ITU-T Recommendation E.164 defines the international number as a country code of one to three digits followed by the national significant number, at most 15 digits in all. Written with a leading +, that becomes the pattern most answers recommend. The Stack Overflow question "Regular expression matching E.164 formatted phone numbers" had about 112,000 views on 2026-09-25.

The pattern encodes exactly three rules:

  1. The string starts with +.
  2. The first digit isn't 0 (no country code starts with 0).
  3. There are 2 to 15 digits and nothing else.

Everything else about a phone number lives in per-country rules: which country codes exist, how long national numbers are in each country, and which leading digits are allocated. None of that fits in a single pattern.

A terminal sends an API request and a JSON response returns true, false and null values.A terminal sends an API request and a JSON response returns true, false and null values.
One REST call. Every answer is true, false or null (unknown).

Which impossible numbers does the regex accept?

We ran eleven inputs through the regex and through libphonenumber-js 1.13.14 (/max metadata) on 2026-09-25. Every row is real output:

InputRegexLibraryWhy
+12matchunparseableTwo digits can't be a phone number anywhere
+999123456789matchunparseable+999 isn't assigned to any country
+2101234567matchunparseable+210 isn't assigned either
+11234567890matchinvalidNorth American area codes never start with 1
+15555555555matchinvalid555 isn't a working area code
+4412345678matchinvalid (length)Too short for a UK number
+447700900123matchinvalidOfcom reserves this range for drama; never assigned
+491511234567890matchinvalidGerman mobile with extra digits, still within 15
+6834002matchvalid, fixed lineA real 7-digit Niue number
+447911123456matchvalid, mobileUK-format mobile
+44 7911 123456no matchvalid, mobileThe regex rejects spaces the user typed

Eight of the eleven strings pass the regex and fail the library. The last row shows the opposite problem: a regex applied to raw user input rejects valid numbers because of formatting. Either way, the regex is answering a different question from the one you asked.

Do the "improved" regex variants help?

Not much. Each tweak moves the error somewhere else. We tested three common variants on five strings in Node.js:

Input^\+?[1-9]\d{1,14}$^\+?\d{10,15}$^\+[1-9]\d{6,14}$
4155552671 (US national, no country)matchmatchno match
+6834002 (valid Niue number)matchno matchmatch
+11234567890 (impossible US area code)matchmatchmatch
0079111234567 (UK number, 00 prefix)no matchmatchno match
+999123456789 (no such country code)matchmatchmatch

Making the + optional is the worst change: 4155552671 then passes as if it were international, although it's a US number written nationally and would be read as +41 (Switzerland). A 10-digit minimum rejects real numbers in small countries. A 7-digit minimum is closer to reality but still accepts every impossible area code and unassigned country code. No length rule can fix a problem that's about which digits are allocated.

What is the minimum length of a valid international phone number?

That Stack Overflow question had about 199,000 views on 2026-09-25, and the honest answer is "it depends on the country". E.164 sets a maximum of 15 digits but no useful minimum. We scanned libphonenumber's metadata (Python phonenumbers 9.0.40) for the shortest valid numbers:

  • 7 digits including the country code for ordinary subscriber numbers in small territories: Niue (+683 4002), Tokelau (+690 3101) and Tristan da Cunha (+290 8999).
  • 6 digits for a handful of special-service numbers, for example 4-digit numbers in Iran (+98 9601).
  • Most countries need far more. A UK number usually has 12 digits with +44, and a German mobile has 12 or 13.

So the popular "at least 10 digits" rule rejects real numbers, and the regex's minimum of 2 digits accepts nonsense. Length is per country, and only country-aware code can check it.

Why not write a regex per country?

Because you'd be rebuilding libphonenumber by hand, and chasing it forever. Google's libphonenumber release notes list 25 releases in 2025 and 19 from January to 23 September 2026. Every one of them updated the phone metadata for at least one region. The 2026-09-23 release alone changed 12 regions, from Bangladesh to Zimbabwe.

A per-country pattern also fails in less obvious ways. ^\+447\d{9}$ looks like "UK mobile", but it matches +447000000000, which is a personal-numbering range, and the reserved drama range +447700900xxx. It also silently assumes +44 means the United Kingdom, while +44 7911 numbers belong to Guernsey. Libraries encode these details in metadata that gets updated. Hand-written patterns rot quietly.

What should you use instead of a regex?

A port of libphonenumber in your language, called in this order: parse the raw input with a default country, check validity, then format as E.164.

JavaScript
import { parsePhoneNumberFromString } from "libphonenumber-js/max";

const p = parsePhoneNumberFromString("+44 7911 123456");
p?.isValid();   // true
p?.number;      // "+447911123456"
p?.country;     // "GG"
Python
import phonenumbers

p = phonenumbers.parse("+1 123 456 7890", None)
phonenumbers.is_possible_number(p)  # True: right length for the US
phonenumbers.is_valid_number(p)     # False: no area code starts with 1

We have step-by-step tutorials for JavaScript and Node, Python and PHP and Laravel. All the ports share Google's metadata, so the same input gives the same answer, as long as the library versions match.

Where does a regex still belong?

In two places.

As a storage invariant. Once a library has normalized a number, the stored string should always match the E.164 shape. A database constraint catches any code path that skips normalization. In PostgreSQL:

SQL
CREATE TABLE contacts (
  id bigint PRIMARY KEY,
  phone_e164 text NOT NULL CHECK (phone_e164 ~ '^\+[1-9][0-9]{6,14}$')
);
INSERT INTO contacts VALUES (1, '+447911123456');  -- ok
INSERT INTO contacts VALUES (2, '07911 123456');   -- ERROR: violates check constraint

We ran this on PostgreSQL 18: the second insert fails with violates check constraint "contacts_phone_e164_check". Note that +11234567890 still passes. The constraint guards the format, not the meaning. The {6,14} lower bound rejects the few 6-digit service numbers; use {5,14} if you need them.

As a cheap pre-filter. Before you parse millions of rows, a loose pattern can throw out obvious junk such as empty cells, e-mail addresses or text. Keep it loose, for example "contains 6 to 20 digits", so it never rejects anything the library would accept.

What can't even a perfect validator tell you?

A number that passes libphonenumber is a number that could exist. Validation doesn't tell you whether it's assigned, in service, a mobile, ported to another network, or used on a messaging app. The next rungs of the ladder need data:

QuestionTool
Is the shape right?Regex (storage invariant only)
Does it fit the country's numbering plan?libphonenumber or a port
Is it a mobile, landline or VoIP line today?Carrier lookup
Is it switched on and reachable?Live network status (HLR); ours is coming soon
Does the person use a given channel?Registration checks, such as WhatsApp

Our API runs the first two rungs on every request for free: numbers are normalized with libphonenumber metadata, invalid ones come back as invalid_number and are never checked or billed. The E.164 guide covers the normalization rules in detail, and HLR vs MNP vs number validation compares the paid rungs.

How should you test your validation?

Use inputs that exercise each rule, and pin the expected results to the library version you ship:

  • One valid number per country you serve, in national and international formats.
  • An impossible area code (+1 123 456 7890), an unassigned country code (+999…), and numbers one digit too short and too long.
  • A shared country code case (+44 7911… returns GG) so your analytics don't assume +44 means GB.
  • Full-width digits and spaces, pasted from PDFs and phones.
  • Reserved fictional ranges for fixtures, never real customer numbers. Our test mode uses Ofcom's drama range, +44 7700 900000 to 900999. libphonenumber rejects that range on purpose, so let it through only when you use a test key.

When a library upgrade changes a result, that's usually the point of the upgrade. Read the release notes, then update the fixture.

What are the key takeaways?

  • ^\+[1-9]\d{1,14}$ checks shape only. In our run, 8 of 11 test strings passed it and failed real validation.
  • Tweaking the pattern (optional +, a 10-digit minimum) trades one failure for another.
  • It accepts unassigned country codes, impossible area codes and wrong lengths, and it rejects valid numbers with spaces.
  • E.164 has no useful minimum length: valid numbers range from 6 or 7 digits (Niue, Tokelau, Iran service numbers) to 15.
  • Per-country regexes go stale. libphonenumber's metadata changed 25 times in 2025.
  • Validate with a libphonenumber port; keep the regex as a database constraint on normalized values.
  • For line type, reachability and channel presence, you need a lookup, not a better pattern.

Sources

  1. ITU-T Recommendation E.164: The international public telecommunication numbering plan — International Telecommunication Union, 2026
  2. List of ITU-T Recommendation E.164 assigned country codes — International Telecommunication Union, 2026
  3. libphonenumber release notes — Google, 2026
  4. Regular expression matching E.164 formatted phone numbers (question 6478875) — Stack Overflow, 2026
  5. What is the minimum length of a valid international phone number? (question 14894899) — Stack Overflow, 2026

Frequently asked questions

What is the regex for an E.164 phone number?

The usual pattern is ^+[1-9]\d{1,14}$: a plus sign, a first digit from 1 to 9, and up to 15 digits in total. It checks the shape of an already-normalized string. It doesn't check whether the country code exists or whether the number is in an allocated range.

What is the minimum length of a valid international phone number?

E.164 sets a maximum of 15 digits but no practical minimum. In libphonenumber's metadata (version 9.0.40), ordinary subscriber numbers in Niue and Tokelau have 7 digits including the country code, and a few special-service numbers have 6.

Can I write a separate regex for each country?

You can, but you would be rebuilding libphonenumber's metadata by hand, and numbering plans change every few weeks. Google published 25 metadata releases in 2025. Use a maintained library and update it.

Is there any good use for an E.164 regex?

Yes: as a storage invariant. After a library has normalized and validated a number, a database CHECK constraint with the E.164 pattern catches code paths that write unnormalized values.

All articles

Know before you send.

Tell us about your use case. We review every request and set you up with test and live keys.