FAILURE MAP
← Case archive

FA-96366 / Phone number formatting / Open access

E.164 parser with trunk prefixes: the first matching country code wins · case 01

"+83..." is parsed as country 8 with a national number starting with 3.

Verified by executionVariant 1 · 11 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The first table entry whose code prefixes the digits is kept, and the one-digit code is listed first.

VERIFIED REPAIR

Keep the matching country with the longest code.

Unsuccessful approach: Reversing the comparison keeps the shortest code, which misparses three-digit codes too.

Case contract

Input [number, default region]. Toy table (cc, trunk, national lengths): DD 8/-/9, AA 42/0/9, BB 83/8/10, CC 891/-/7-8. Remove "(0)" and keep digits. A leading "+" or "00" means international: drop "00", pick the country with the longest matching code. Otherwise the region is used and a national number of a trunk country must start with its trunk, which is removed once. The national part must have an allowed length. Return "+" cc national or None.

Why this case matters

Canonical E.164 storage is the join key for calls, messaging and deduplication; one wrong prefix rule routes numbers to another country.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    num, region = x
    TABLE = {'DD': ('8', '', (9,)), 'AA': ('42', '0', (9,)), 'BB': ('83', '8', (10,)), 'CC': ('891', '', (7, 8))}
    s = num.strip().replace('(0)', '')
    raw = ''.join(c for c in s if c.isdigit())
    if s.startswith('+') or raw.startswith('00'):
        if not s.startswith('+'):
            raw = raw[2:]
        best = None
        for code, (cc, trunk, lens) in TABLE.items():
            if raw.startswith(cc) and best is None:
                best = code
        if best is None:
            return None
        cc, trunk, lens = TABLE[best]
        nat = raw[len(cc):]
    else:
        if region not in TABLE:
            return None
        cc, trunk, lens = TABLE[region]
        if trunk:
            if not raw.startswith(trunk):
                return None
            raw = raw[len(trunk):]
        nat = raw
    if len(nat) not in lens:
        return None
    return '+' + cc + nat
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['national with trunk zero', ['0555011234', 'AA'], '+42555011234'], ['national missing its trunk', ['555011234', 'AA'], None], ['ten digits without trunk', ['5555011234', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550111', 'BB'], '+838125550111'], ['international two-digit code', ['+83 8125550111', 'AA'], '+838125550111'], ['double-zero international prefix', ['0083 8125550111', 'CC'], '+838125550111'], ['parenthesized trunk in international form', ['+42 (0)555011234', 'BB'], '+42555011234'], ['one-digit country code', ['+8 555011223', 'AA'], '+8555011223'], ['three-digit country code', ['+891 5550113', 'BB'], '+8915550113'], ['international with wrong length', ['+83 555011234', 'AA'], None], ['national without trunk country', ['5550113', 'CC'], '+8915550113']], [['national with trunk zero', ['0555012345', 'AA'], '+42555012345'], ['national missing its trunk', ['555012345', 'AA'], None], ['ten digits without trunk', ['5555012345', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550122', 'BB'], '+838125550122'], ['international two-digit code', ['+83 8125550122', 'AA'], '+838125550122'], ['double-zero international prefix', ['0083 8125550122', 'CC'], '+838125550122'], ['parenthesized trunk in international form', ['+42 (0)555012345', 'BB'], '+42555012345'], ['one-digit country code', ['+8 555022334', 'AA'], '+8555022334'], ['three-digit country code', ['+891 5550124', 'BB'], '+8915550124'], ['international with wrong length', ['+83 555012345', 'AA'], None], ['national without trunk country', ['5550124', 'CC'], '+8915550124']], [['national with trunk zero', ['0555013456', 'AA'], '+42555013456'], ['national missing its trunk', ['555013456', 'AA'], None], ['ten digits without trunk', ['5555013456', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550133', 'BB'], '+838125550133'], ['international two-digit code', ['+83 8125550133', 'AA'], '+838125550133'], ['double-zero international prefix', ['0083 8125550133', 'CC'], '+838125550133'], ['parenthesized trunk in international form', ['+42 (0)555013456', 'BB'], '+42555013456'], ['one-digit country code', ['+8 555033445', 'AA'], '+8555033445'], ['three-digit country code', ['+891 5550135', 'BB'], '+8915550135'], ['international with wrong length', ['+83 555013456', 'AA'], None], ['national without trunk country', ['5550135', 'CC'], '+8915550135']], [['national with trunk zero', ['0555014567', 'AA'], '+42555014567'], ['national missing its trunk', ['555014567', 'AA'], None], ['ten digits without trunk', ['5555014567', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550144', 'BB'], '+838125550144'], ['international two-digit code', ['+83 8125550144', 'AA'], '+838125550144'], ['double-zero international prefix', ['0083 8125550144', 'CC'], '+838125550144'], ['parenthesized trunk in international form', ['+42 (0)555014567', 'BB'], '+42555014567'], ['one-digit country code', ['+8 555044556', 'AA'], '+8555044556'], ['three-digit country code', ['+891 5550146', 'BB'], '+8915550146'], ['international with wrong length', ['+83 555014567', 'AA'], None], ['national without trunk country', ['5550146', 'CC'], '+8915550146']], [['national with trunk zero', ['0555015678', 'AA'], '+42555015678'], ['national missing its trunk', ['555015678', 'AA'], None], ['ten digits without trunk', ['5555015678', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550155', 'BB'], '+838125550155'], ['international two-digit code', ['+83 8125550155', 'AA'], '+838125550155'], ['double-zero international prefix', ['0083 8125550155', 'CC'], '+838125550155'], ['parenthesized trunk in international form', ['+42 (0)555015678', 'BB'], '+42555015678'], ['one-digit country code', ['+8 555055667', 'AA'], '+8555055667'], ['three-digit country code', ['+891 5550157', 'BB'], '+8915550157'], ['international with wrong length', ['+83 555015678', 'AA'], None], ['national without trunk country', ['5550157', 'CC'], '+8915550157']]]
for label, arg, expected in fixtures[N - 1]:
    check(label, solve(arg), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
national with trunk zero+42555011234+42555011234Passed
national missing its trunkNoneNonePassed
ten digits without trunkNoneNonePassed
national whose number repeats the trunk digit+838125550111+838125550111Passed
international two-digit codeNone+838125550111Failed
double-zero international prefixNone+838125550111Failed
parenthesized trunk in international form+42555011234+42555011234Passed
one-digit country code+8555011223+8555011223Passed
three-digit country code+8915550113+8915550113Passed
international with wrong lengthNoneNonePassed
national without trunk country+8915550113+8915550113Passed

SHA-256 / 3cb459aff8311e5d515e4a01d4aea11643f1c5b4fa023769c44791a3cd354ea4

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    num, region = x
    TABLE = {'DD': ('8', '', (9,)), 'AA': ('42', '0', (9,)), 'BB': ('83', '8', (10,)), 'CC': ('891', '', (7, 8))}
    s = num.strip().replace('(0)', '')
    raw = ''.join(c for c in s if c.isdigit())
    if s.startswith('+') or raw.startswith('00'):
        if not s.startswith('+'):
            raw = raw[2:]
        best = None
        for code, (cc, trunk, lens) in TABLE.items():
            if raw.startswith(cc) and (best is None or len(cc) < len(TABLE[best][0])):
                best = code
        if best is None:
            return None
        cc, trunk, lens = TABLE[best]
        nat = raw[len(cc):]
    else:
        if region not in TABLE:
            return None
        cc, trunk, lens = TABLE[region]
        if trunk:
            if not raw.startswith(trunk):
                return None
            raw = raw[len(trunk):]
        nat = raw
    if len(nat) not in lens:
        return None
    return '+' + cc + nat
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['national with trunk zero', ['0555011234', 'AA'], '+42555011234'], ['national missing its trunk', ['555011234', 'AA'], None], ['ten digits without trunk', ['5555011234', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550111', 'BB'], '+838125550111'], ['international two-digit code', ['+83 8125550111', 'AA'], '+838125550111'], ['double-zero international prefix', ['0083 8125550111', 'CC'], '+838125550111'], ['parenthesized trunk in international form', ['+42 (0)555011234', 'BB'], '+42555011234'], ['one-digit country code', ['+8 555011223', 'AA'], '+8555011223'], ['three-digit country code', ['+891 5550113', 'BB'], '+8915550113'], ['international with wrong length', ['+83 555011234', 'AA'], None], ['national without trunk country', ['5550113', 'CC'], '+8915550113']], [['national with trunk zero', ['0555012345', 'AA'], '+42555012345'], ['national missing its trunk', ['555012345', 'AA'], None], ['ten digits without trunk', ['5555012345', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550122', 'BB'], '+838125550122'], ['international two-digit code', ['+83 8125550122', 'AA'], '+838125550122'], ['double-zero international prefix', ['0083 8125550122', 'CC'], '+838125550122'], ['parenthesized trunk in international form', ['+42 (0)555012345', 'BB'], '+42555012345'], ['one-digit country code', ['+8 555022334', 'AA'], '+8555022334'], ['three-digit country code', ['+891 5550124', 'BB'], '+8915550124'], ['international with wrong length', ['+83 555012345', 'AA'], None], ['national without trunk country', ['5550124', 'CC'], '+8915550124']], [['national with trunk zero', ['0555013456', 'AA'], '+42555013456'], ['national missing its trunk', ['555013456', 'AA'], None], ['ten digits without trunk', ['5555013456', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550133', 'BB'], '+838125550133'], ['international two-digit code', ['+83 8125550133', 'AA'], '+838125550133'], ['double-zero international prefix', ['0083 8125550133', 'CC'], '+838125550133'], ['parenthesized trunk in international form', ['+42 (0)555013456', 'BB'], '+42555013456'], ['one-digit country code', ['+8 555033445', 'AA'], '+8555033445'], ['three-digit country code', ['+891 5550135', 'BB'], '+8915550135'], ['international with wrong length', ['+83 555013456', 'AA'], None], ['national without trunk country', ['5550135', 'CC'], '+8915550135']], [['national with trunk zero', ['0555014567', 'AA'], '+42555014567'], ['national missing its trunk', ['555014567', 'AA'], None], ['ten digits without trunk', ['5555014567', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550144', 'BB'], '+838125550144'], ['international two-digit code', ['+83 8125550144', 'AA'], '+838125550144'], ['double-zero international prefix', ['0083 8125550144', 'CC'], '+838125550144'], ['parenthesized trunk in international form', ['+42 (0)555014567', 'BB'], '+42555014567'], ['one-digit country code', ['+8 555044556', 'AA'], '+8555044556'], ['three-digit country code', ['+891 5550146', 'BB'], '+8915550146'], ['international with wrong length', ['+83 555014567', 'AA'], None], ['national without trunk country', ['5550146', 'CC'], '+8915550146']], [['national with trunk zero', ['0555015678', 'AA'], '+42555015678'], ['national missing its trunk', ['555015678', 'AA'], None], ['ten digits without trunk', ['5555015678', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550155', 'BB'], '+838125550155'], ['international two-digit code', ['+83 8125550155', 'AA'], '+838125550155'], ['double-zero international prefix', ['0083 8125550155', 'CC'], '+838125550155'], ['parenthesized trunk in international form', ['+42 (0)555015678', 'BB'], '+42555015678'], ['one-digit country code', ['+8 555055667', 'AA'], '+8555055667'], ['three-digit country code', ['+891 5550157', 'BB'], '+8915550157'], ['international with wrong length', ['+83 555015678', 'AA'], None], ['national without trunk country', ['5550157', 'CC'], '+8915550157']]]
for label, arg, expected in fixtures[N - 1]:
    check(label, solve(arg), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
national with trunk zero+42555011234+42555011234Passed
national missing its trunkNoneNonePassed
ten digits without trunkNoneNonePassed
national whose number repeats the trunk digit+838125550111+838125550111Passed
international two-digit codeNone+838125550111Failed
double-zero international prefixNone+838125550111Failed
parenthesized trunk in international form+42555011234+42555011234Passed
one-digit country code+8555011223+8555011223Passed
three-digit country code+8915550113+8915550113Passed
international with wrong lengthNoneNonePassed
national without trunk country+8915550113+8915550113Passed

SHA-256 / 552baa7dd10a8af8f0cb7f06412123ffd9c9710e56123a8fdac7a6ffea7491a0

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    num, region = x
    TABLE = {'DD': ('8', '', (9,)), 'AA': ('42', '0', (9,)), 'BB': ('83', '8', (10,)), 'CC': ('891', '', (7, 8))}
    s = num.strip().replace('(0)', '')
    raw = ''.join(c for c in s if c.isdigit())
    if s.startswith('+') or raw.startswith('00'):
        if not s.startswith('+'):
            raw = raw[2:]
        best = None
        for code, (cc, trunk, lens) in TABLE.items():
            if raw.startswith(cc) and (best is None or len(cc) > len(TABLE[best][0])):
                best = code
        if best is None:
            return None
        cc, trunk, lens = TABLE[best]
        nat = raw[len(cc):]
    else:
        if region not in TABLE:
            return None
        cc, trunk, lens = TABLE[region]
        if trunk:
            if not raw.startswith(trunk):
                return None
            raw = raw[len(trunk):]
        nat = raw
    if len(nat) not in lens:
        return None
    return '+' + cc + nat
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['national with trunk zero', ['0555011234', 'AA'], '+42555011234'], ['national missing its trunk', ['555011234', 'AA'], None], ['ten digits without trunk', ['5555011234', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550111', 'BB'], '+838125550111'], ['international two-digit code', ['+83 8125550111', 'AA'], '+838125550111'], ['double-zero international prefix', ['0083 8125550111', 'CC'], '+838125550111'], ['parenthesized trunk in international form', ['+42 (0)555011234', 'BB'], '+42555011234'], ['one-digit country code', ['+8 555011223', 'AA'], '+8555011223'], ['three-digit country code', ['+891 5550113', 'BB'], '+8915550113'], ['international with wrong length', ['+83 555011234', 'AA'], None], ['national without trunk country', ['5550113', 'CC'], '+8915550113']], [['national with trunk zero', ['0555012345', 'AA'], '+42555012345'], ['national missing its trunk', ['555012345', 'AA'], None], ['ten digits without trunk', ['5555012345', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550122', 'BB'], '+838125550122'], ['international two-digit code', ['+83 8125550122', 'AA'], '+838125550122'], ['double-zero international prefix', ['0083 8125550122', 'CC'], '+838125550122'], ['parenthesized trunk in international form', ['+42 (0)555012345', 'BB'], '+42555012345'], ['one-digit country code', ['+8 555022334', 'AA'], '+8555022334'], ['three-digit country code', ['+891 5550124', 'BB'], '+8915550124'], ['international with wrong length', ['+83 555012345', 'AA'], None], ['national without trunk country', ['5550124', 'CC'], '+8915550124']], [['national with trunk zero', ['0555013456', 'AA'], '+42555013456'], ['national missing its trunk', ['555013456', 'AA'], None], ['ten digits without trunk', ['5555013456', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550133', 'BB'], '+838125550133'], ['international two-digit code', ['+83 8125550133', 'AA'], '+838125550133'], ['double-zero international prefix', ['0083 8125550133', 'CC'], '+838125550133'], ['parenthesized trunk in international form', ['+42 (0)555013456', 'BB'], '+42555013456'], ['one-digit country code', ['+8 555033445', 'AA'], '+8555033445'], ['three-digit country code', ['+891 5550135', 'BB'], '+8915550135'], ['international with wrong length', ['+83 555013456', 'AA'], None], ['national without trunk country', ['5550135', 'CC'], '+8915550135']], [['national with trunk zero', ['0555014567', 'AA'], '+42555014567'], ['national missing its trunk', ['555014567', 'AA'], None], ['ten digits without trunk', ['5555014567', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550144', 'BB'], '+838125550144'], ['international two-digit code', ['+83 8125550144', 'AA'], '+838125550144'], ['double-zero international prefix', ['0083 8125550144', 'CC'], '+838125550144'], ['parenthesized trunk in international form', ['+42 (0)555014567', 'BB'], '+42555014567'], ['one-digit country code', ['+8 555044556', 'AA'], '+8555044556'], ['three-digit country code', ['+891 5550146', 'BB'], '+8915550146'], ['international with wrong length', ['+83 555014567', 'AA'], None], ['national without trunk country', ['5550146', 'CC'], '+8915550146']], [['national with trunk zero', ['0555015678', 'AA'], '+42555015678'], ['national missing its trunk', ['555015678', 'AA'], None], ['ten digits without trunk', ['5555015678', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550155', 'BB'], '+838125550155'], ['international two-digit code', ['+83 8125550155', 'AA'], '+838125550155'], ['double-zero international prefix', ['0083 8125550155', 'CC'], '+838125550155'], ['parenthesized trunk in international form', ['+42 (0)555015678', 'BB'], '+42555015678'], ['one-digit country code', ['+8 555055667', 'AA'], '+8555055667'], ['three-digit country code', ['+891 5550157', 'BB'], '+8915550157'], ['international with wrong length', ['+83 555015678', 'AA'], None], ['national without trunk country', ['5550157', 'CC'], '+8915550157']]]
for label, arg, expected in fixtures[N - 1]:
    check(label, solve(arg), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
national with trunk zero+42555011234+42555011234Passed
national missing its trunkNoneNonePassed
ten digits without trunkNoneNonePassed
national whose number repeats the trunk digit+838125550111+838125550111Passed
international two-digit code+838125550111+838125550111Passed
double-zero international prefix+838125550111+838125550111Passed
parenthesized trunk in international form+42555011234+42555011234Passed
one-digit country code+8555011223+8555011223Passed
three-digit country code+8915550113+8915550113Passed
international with wrong lengthNoneNonePassed
national without trunk country+8915550113+8915550113Passed

SHA-256 / a5fcde9868b1dc678208edee6e790bb754bafaf6cf02a25f9b0a8efb584d2a82

Verification & scope

A deterministic toy contract over synthetic, obviously fictitious telephone numbers and toy country tables. The rules are stipulated for this model only and make no claim of conformance with any numbering plan or telecommunications standard. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:52:22.061369+00:00.

Case digest / 2b1b8d731abc0db64161c87144d27146ef204f6f075c968708d585f1898a0cf5