signalapp/Signal-Server · error · NotAuthorizedException
registration session is unverified
Error message
registration session is unverified
What it means
During changeNumber, the registration session tied to the new phone number must be verified (e.g. SMS/voice challenge completed). If the RegistrationService reports UnverifiedRegistrationSessionException, the server responds 401 NotAuthorizedException('registration session is unverified'), meaning the session exists but its verification step was never completed.
Solutions
- Complete the registration session verification (submit the SMS/voice code) via the registration service before calling change-number.
- Create a fresh registration session, verify it, then retry the change-number request with that session id.
- Check session expiry and restart the flow if the verification window lapsed.
- Ensure the session id sent matches the session used to verify the new number.
Example fix
// before changeNumber(sessionId); // session created but code never submitted // after registrationClient.verifySession(sessionId, smsCode); changeNumber(sessionId);
Defensive patterns
Strategy: retry
Validate before calling
const session = await getSession(sessionId);
if (session.status !== 'verified') throw new Error('complete session verification first'); Type guard
const isVerifiedSession = (s) => s && s.verified === true;
Try / catch
try { await changeNumber(req); } catch (e) { if (e.status === 401 && e.message.includes('unverified')) { await submitVerificationCode(sessionId, code); return changeNumber(req); } throw e; } Prevention
- Always complete the SMS/voice challenge before submitting change-number
- Create fresh sessions when verification windows expire
- Ensure the session id matches the number being changed
When it happens
Trigger: PUT /v2/accounts/phone_number/{number} where the referenced registration session (session id in request) has not passed the required verification challenge for the new number.
Common situations: Client submitted the change-number request before the user entered the SMS code, session verification expired, or the client used a session created for a different flow/number.
Related errors
- registration session is unverified
- number does not match session
- Missing required device capability
- recovery password could not be verified
- login purchases are not enabled
AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09).
Data as JSON: /api/errors/9331dc5d7161334a.
Report an issue: GitHub.
Appendix: source
Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountControllerV2.java:138
throw new WebApplicationException(Response.status(410)
.type(MediaType.APPLICATION_JSON)
.entity(new StaleDevicesResponse(e.getMismatchedDevices().staleDeviceIds()))
.build());
} else {
throw new WebApplicationException(Response.status(409)
.type(MediaType.APPLICATION_JSON_TYPE)
.entity(new MismatchedDevicesResponse(e.getMismatchedDevices().missingDeviceIds(),
e.getMismatchedDevices().extraDeviceIds()))
.build());
}
} catch (final IllegalArgumentException e) {
throw new BadRequestException(e);
} catch (final MessageTooLargeException e) {
throw new WebApplicationException(Response.Status.REQUEST_ENTITY_TOO_LARGE);
} catch (final MessageDeliveryNotAllowedException e) {
throw new ServiceUnavailableException();
} catch (final UnverifiedRegistrationSessionException e) {
throw new NotAuthorizedException("registration session is unverified");
} catch (final InvalidRegistrationSessionException e) {
throw new BadRequestException(e.getMessage());
} catch (final IOException e) {
throw new ServiceUnavailableException(e.getMessage());
} catch (final RecoveryPasswordVerificationFailedException e) {
throw new ForbiddenException("recovery password could not be verified");
}
}
@PUT
@Path("/phone_number_discoverability")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Sets whether the account should be discoverable by phone number in the directory.")
@ApiResponse(responseCode = "204", description = "The setting was successfully updated.")
public void setPhoneNumberDiscoverability(
@Auth AuthenticatedDevice auth,
@NotNull @Valid PhoneNumberDiscoverabilityRequest phoneNumberDiscoverability) {View on GitHub (pinned to 100ab61c82)