signalapp/Signal-Server · warning · BadRequestException

login purchases are not enabled

Error message

login purchases are not enabled

What it means

registerAccountWithoutNumber (called from the /v1/registration flow in RegistrationController) rejects login-purchase registrations when the feature is switched off. The controller checks DynamicConfigurationManager's LoginPurchaseConfiguration.enabled() and throws a BadRequestException (HTTP 400) immediately if the server has not enabled the feature. It is a server-side feature gate, not a client error.

Solutions

  1. Enable the feature in the server's dynamic configuration: set loginPurchaseConfiguration.enabled() to true and allow the config to propagate to the server.
  2. Verify the deployed dynamic configuration actually contains the loginPurchaseConfiguration block and that the server picked it up (check config file and reload).
  3. If you are a client developer, treat HTTP 400 'login purchases are not enabled' as feature-disabled and fall back to the normal (non-purchase) registration path.
  4. Confirm you are targeting the intended server deployment; a staging server with the flag off will reject requests meant for production.

Example fix

// server config (before)
loginPurchase:
  enabled: false
// after
loginPurchase:
  enabled: true
Defensive patterns

Strategy: fallback

Try / catch

try {
  registerWithoutNumber(request);
} catch (BadRequestException e) {
  if ("login purchases are not enabled".equals(e.getMessage())) {
    fallBackToStandardRegistration(request); // feature-off path
  } else throw e;
}

Prevention

When it happens

Trigger: A client POSTs to the registration endpoint with a receipt credential / login-purchase flow while the server operator's dynamic configuration has loginPurchaseConfiguration.enabled() set to false (or the config field is absent/default-disabled).

Common situations: Self-hosted or staging Signal servers where the login-purchase feature flag was never enabled; environments where the dynamic configuration YAML lacks the loginPurchase section (so defaults to disabled); production operators disabling the feature without coordinating with client releases that rely on it.

Related errors


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

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/RegistrationController.java:334

    final AccountIdentityResponse identityResponse = new AccountIdentityResponseBuilder(account)
        // If there was an existing account, return whether it could have had something in the storage service
        .storageCapable(existingAccount
            .map(a -> a.hasCapability(DeviceCapability.STORAGE))
            .orElse(false))
        .build();

    return new AccountCreationResponse(identityResponse, existingAccount.isPresent());
  }

  private AccountCreationResponse registerAccountWithoutNumber(
      final String password,
      final RegistrationRequest registrationRequest,
      final String userAgent,
      final String signalAgent) {

    if (!dynamicConfigurationManager.getConfiguration().getLoginPurchaseConfiguration().enabled()) {
      throw new BadRequestException("login purchases are not enabled");
    }

    registrationRequest.accountAttributes().recoveryPassword()
        .filter(ArrayUtils::isNotEmpty)
        .orElseThrow(() -> new WebApplicationException("Account recovery password is required", 422));

    final ReceiptCredentialPresentation receiptCredentialPresentation;
    try {
      receiptCredentialPresentation = receiptCredentialPresentationFactory
          .build(registrationRequest.receiptCredentialPresentation());
    } catch (InvalidInputException _) {
      throw new BadRequestException("Invalid receipt credential presentation");
    }
    try {
      serverZkReceiptOperations.verifyReceiptCredentialPresentation(receiptCredentialPresentation);
    } catch (VerificationFailedException _) {
      throw new NotAuthorizedException("Receipt credential presentation verification failed");
    }

View on GitHub (pinned to 100ab61c82)