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
- Re-register the device's push token (APNs/FCM) so the account has a push channel
- Remove stale devices from the account via linked-device management
- Verify the client completed device provisioning/registration before requesting push challenges
- 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
- Register push tokens immediately after app install/reinstall
- Prune unlinked/stale devices from accounts
- Verify push provider credentials on the server
- Re-provision after notification permission changes
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
- return Response.status(429).build();
- return Response.status(411)
- return Response.status(503).build();
- return Response.status(422).build();
- Empty body not allowed
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)