signalapp/Signal-Server · error · ServerErrorException
could not parse already validated number
Error message
could not parse already validated number
What it means
createSession throws this ServerErrorException (HTTP 500) when a phone number that was already validated upstream cannot be re-parsed or canonicalized by Util.canonicalizePhoneNumber after PhoneNumberUtil.parse. Since the number was previously validated, this indicates an internal invariant violation rather than bad client input. It signals corrupted or malformed session data on the server side.
Solutions
- Inspect the exact number value sent in the request; ensure it is in E.164 format (e.g. +14155552671) before calling the endpoint.
- Check server-side Util.canonicalizePhoneNumber and libphonenumber version for a regression or mismatch with the validation path.
- Log the NumberParseException in createSession to identify the failing parse mode and fix the offending stored/forwarded number.
- If you operate the service, normalize numbers to E.164 at ingestion so parse+canonicalize cannot fail.
Example fix
// before String number = request.number(); // e.g. "(415) 555-2671" // after String number = "+14155552671"; // E.164, pre-canonicalized client-side
Defensive patterns
Strategy: validation
Validate before calling
// libphonenumber-js
const parsed = parsePhoneNumberFromString(number);
if (!parsed || !parsed.isValid()) throw new Error('send E.164 number');
const e164 = parsed.number; // e.g. "+14155552671" Prevention
- Always send E.164-formatted numbers
- Validate client-side with libphonenumber before the API call
- Keep client/server libphonenumber versions aligned
When it happens
Trigger: POST to the verification session creation endpoint where request.number() parses during initial validation but Util.canonicalizePhoneNumber(PhoneNumberUtil.getInstance().parse(request.number(), null)) throws NumberParseException — i.e. the canonicalization/parse round-trip fails on an already-accepted number format.
Common situations: Numbers stored or forwarded in a format the server's libphonenumber instance cannot re-parse (unusual regional formats, invalid region hints, whitespace/unicode artifacts); version drift between validation and canonicalization code paths; a client sending a number form that passed earlier validation but is not canonical.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- interrupted during delivery
- delivery cancelled
- failure during delivery
- 500 Internal Server Error (registration service failure)
- value is not in E164 format
AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09).
Data as JSON: /api/errors/b856e81e392c754d.
Report an issue: GitHub.
Appendix: source
Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/VerificationController.java:207
""")
@ApiResponse(responseCode = "200", description = "The verification session was created successfully", useReturnTypeSchema = true)
@ApiResponse(responseCode = "422", description = "The request did not pass validation")
@ApiResponse(responseCode = "429", description = "Too many attempts", headers = @Header(
name = "Retry-After",
description = "If present, an positive integer indicating the number of seconds before a subsequent attempt could succeed",
schema = @Schema(implementation = Integer.class)))
public VerificationSessionResponse createSession(@NotNull @Valid final CreateVerificationSessionRequest request,
@Context final ContainerRequestContext requestContext)
throws RateLimitExceededException, ObsoletePhoneNumberFormatException {
final Pair<String, PushNotification.TokenType> pushTokenAndType = validateAndExtractPushToken(
request.updateVerificationSessionRequest());
final Phonenumber.PhoneNumber phoneNumber;
try {
phoneNumber = Util.canonicalizePhoneNumber(PhoneNumberUtil.getInstance().parse(request.number(), null));
} catch (final NumberParseException e) {
throw new ServerErrorException("could not parse already validated number", Response.Status.INTERNAL_SERVER_ERROR);
}
Optional<CarrierData> maybeCarrierData;
if (dynamicConfigurationManager.getConfiguration().getCarrierDataLookupConfiguration().enabled()) {
try {
maybeCarrierData = carrierDataProvider.lookupCarrierData(phoneNumber,
dynamicConfigurationManager.getConfiguration().getCarrierDataLookupConfiguration().maxCacheAge());
} catch (final IOException | CarrierDataException e) {
logger.warn("Failed to retrieve carrier data", e);
maybeCarrierData = Optional.empty();
}
} else {
maybeCarrierData = Optional.empty();
}
final RegistrationServiceSession registrationServiceSession =
registrationServiceClient.createRegistrationSession(phoneNumber,View on GitHub (pinned to 100ab61c82)