signalapp/Signal-Server · error

return Response.status(404).build();

Error message

return Response.status(404).build();

What it means

The push-challenge endpoint returns HTTP 404 when rateLimitChallengeManager.sendPushChallenge(account) throws NotPushRegisteredException, meaning none of the account's devices currently holds a valid push token/channel. The server cannot deliver the push challenge because there is no registered push destination for the account.

Solutions

  1. Re-register the device's push token (APNs/FCM) so the account has a push channel
  2. Remove stale devices from the account via linked-device management
  3. Verify the client completed device provisioning/registration before requesting push challenges
  4. Check server-side push credential configuration (APNs keys, FCM sender) if all accounts 404

Example fix

// before
challengeClient.requestPushChallenge();
// after
try {
  challengeClient.requestPushChallenge();
} catch (HttpURLConnection404) {
  pushTokenManager.registerNewToken(); // re-establish push channel, then retry
}
Defensive patterns

Strategy: validation

Validate before calling

// ensure a push token exists before requesting a push challenge
if (!pushTokenRegistry.hasValidToken(account)) {
  pushTokenRegistry.registerToken(); // FCM/APNs
}
challengeClient.requestPushChallenge();

Type guard

boolean hasPushChannel(Account a) {
  return a.getDevices().stream().anyMatch(d -> d.getPushToken() != null && !d.getPushToken().isBlank());
}

Try / catch

try { challengeClient.requestPushChallenge(); }
catch (NotFoundException e) {
  reRegisterPushToken();
  retryOnce();
}

Prevention

When it happens

Trigger: Calling POST /v1/challenge/push for an account whose devices have no active APNs/FCM registration (unregistered or stale push credentials).

Common situations: Client reinstalled the app or revoked notification permissions so the push token was never re-registered; stale device entries after account recovery; testing against accounts that never registered with push providers.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java:199

      description = "If present, an positive integer indicating the number of seconds before a subsequent attempt could succeed"))
  @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"))
  public Response requestPushChallenge(@Auth final AuthenticatedDevice auth,
      @Context ContainerRequestContext requestContext) {

    final Account account = accountsManager.getByAccountIdentifier(auth.accountIdentifier())
        .orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED));

    final ChallengeConstraints constraints = challengeConstraintChecker.challengeConstraintsHttp(requestContext, account);
    if (!constraints.pushPermitted()) {
      return Response.status(429).build();
    }
    try {
      rateLimitChallengeManager.sendPushChallenge(account);
      return Response.status(200).build();
    } catch (final NotPushRegisteredException e) {
      return Response.status(404).build();
    }
  }
}

View on GitHub (pinned to 100ab61c82)