signalapp/Signal-Server · error · ObsoletePhoneNumberFormatException

bj

Error message

bj

What it means

canonicalizePhoneNumber throws ObsoletePhoneNumberFormatException with message "bj" when the given number matches Signal's old Benin phone number format. Benin changed its numbering plan (old 8-digit numbers were prefixed), so numbers in the legacy format are deliberately rejected instead of being silently canonicalized. Callers must migrate the number to the new format or reject the account identifier.

Solutions

  1. Reformat the number to Benin's new numbering plan (prefix the old national number per the regulator's migration rule, e.g. prepend the mandated digit(s)) before canonicalizing.
  2. Have the user re-register/update their phone number to the new format.
  3. Catch ObsoletePhoneNumberFormatException and treat the identifier as obsolete: prompt for re-verification rather than sending to the old number.
  4. Update stored records via a migration that rewrites legacy Benin numbers to the new format.
  5. Exclude obsolete-format numbers from bulk operations and log them for remediation.

Example fix

// before
Phonenumber.PhoneNumber n = phoneUtil.parse("+229 90 12 34 56", null);
Phonenumber.PhoneNumber canonical = Util.canonicalizePhoneNumber(n); // throws
// after
Phonenumber.PhoneNumber n = phoneUtil.parse("+229 0190 12 34 56", null);
Phonenumber.PhoneNumber canonical = Util.canonicalizePhoneNumber(n); // new numbering plan
Defensive patterns

Strategy: validation

Validate before calling

// before canonicalizing
Phonenumber.PhoneNumber n = phoneUtil.parse(raw, null);
if (n.getCountryCode() == 229 && String.valueOf(n.getNationalNumber()).length() == 8) {
    // legacy Benin format: apply the regulator's migration prefix first
    n = new Phonenumber.PhoneNumber().setCountryCode(229)
        .setNationalNumber(Long.parseLong("01" + n.getNationalNumber()));
}
Phonenumber.PhoneNumber canonical = Util.canonicalizePhoneNumber(n);

Try / catch

try {
    canonical = Util.canonicalizePhoneNumber(number);
} catch (ObsoletePhoneNumberFormatException e) {
    // "bj": legacy Benin numbering plan
    markNumberObsolete(number);
    throw new WebApplicationException(Status.BAD_REQUEST);
}

Prevention

When it happens

Trigger: Calling Util.canonicalizePhoneNumber with a Phonenumber.PhoneNumber whose national number matches the legacy Benin (country code 229) pattern detected by isOldFormatBeninPhoneNumber, e.g. an 8-digit Benin subscriber number from before the 2024 numbering change.

Common situations: Long-lived accounts registered with old Benin numbers; data imported from old backups; clients that never re-registered after Benin's numbering plan change; bulk migration scripts processing pre-change contact lists.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/70a07f64db7ffec8. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/util/Util.java:239

   * @param phoneNumber the phone number to check.
   * @return whether the provided phone number is an old-format Benin phone number
   */
  public static boolean isOldFormatBeninPhoneNumber(final Phonenumber.PhoneNumber phoneNumber) {
    return "BJ".equals(PHONE_NUMBER_UTIL.getRegionCodeForNumber(phoneNumber)) &&
        PHONE_NUMBER_UTIL.getNationalSignificantNumber(phoneNumber).length() == 8;
  }

  /**
   * If applicable, return the canonical form of the provided phone number.
   * This is relevant in cases where a numbering authority has changed the numbering format for a region.
   *
   * @param phoneNumber the phone number to canonicalize.
   * @return the canonical phone number if applicable, otherwise the original phone number.
   */
  public static Phonenumber.PhoneNumber canonicalizePhoneNumber(final Phonenumber.PhoneNumber phoneNumber)
      throws NumberParseException, ObsoletePhoneNumberFormatException {
    if (isOldFormatBeninPhoneNumber(phoneNumber)) {
      throw new ObsoletePhoneNumberFormatException("bj");
    }
    return phoneNumber;
  }

  public static byte[] truncate(byte[] element, int length) {
    byte[] result = new byte[length];
    System.arraycopy(element, 0, result, 0, result.length);

    return result;
  }

  public static void sleep(long i) {
    try {
      Thread.sleep(i);
    } catch (final InterruptedException ignored) {
    }
  }

View on GitHub (pinned to 100ab61c82)