{"record":{"id":"cf0f68f135da91a4","repo":"signalapp/Signal-Server","slug":"return-response-status-428-build","errorCode":null,"errorMessage":"return Response.status(428).build();","messagePattern":"return Response\\.status\\(428\\)\\.build\\(\\);","errorType":"http","errorClass":null,"httpStatus":428,"severity":"warning","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java","lineNumber":124,"sourceCode":"\n        if (!constraints.pushPermitted()) {\n          return Response.status(429).build();\n        }\n        rateLimitChallengeManager.answerPushChallenge(account, pushChallengeRequest.getChallenge());\n      } else if (answerRequest instanceof final AnswerCaptchaChallengeRequest captchaChallengeRequest) {\n        tags = tags.and(CHALLENGE_TYPE_TAG, \"captcha\");\n\n        final String remoteAddress = (String) requestContext.getProperty(\n            RemoteAddressFilter.REMOTE_ADDRESS_ATTRIBUTE_NAME);\n        final boolean success = rateLimitChallengeManager.answerCaptchaChallenge(\n            account,\n            captchaChallengeRequest.getCaptcha(),\n            remoteAddress,\n            userAgent,\n            constraints.captchaScoreThreshold());\n\n        if (!success) {\n          return Response.status(428).build();\n        }\n\n      } else {\n        tags = tags.and(CHALLENGE_TYPE_TAG, \"unrecognized\");\n      }\n    } catch (final InvalidCaptchaArgumentException e) {\n      return Response.status(Response.Status.BAD_REQUEST.getStatusCode(), e.getMessage()).build();\n    } catch (final IOException e) {\n      logger.error(\"error assessing captcha during challenge response handling\", e);\n      return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();\n    } finally {\n      Metrics.counter(CHALLENGE_RESPONSE_COUNTER_NAME, tags).increment();\n    }\n\n    return Response.status(200).build();\n  }\n\n  @POST","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ChallengeController.java#L106-L142","documentation":"ChallengeController's captcha verification path returns HTTP 428 (Precondition Required) when the captcha token supplied by the client fails verification at the configured score threshold. It is not an exception but a deliberate guard response signaling the client must pass a valid challenge before proceeding.","triggerScenarios":"POSTing a challenge response with a captcha whose score (as evaluated by the captcha service against remoteAddress/userAgent and constraints.captchaScoreThreshold()) comes back success=false.","commonSituations":"Stale or already-used captcha tokens; bots/low-score traffic; user behind datacenter IP causing low score; captcha service outage or misconfigured site key/secret; score threshold set too aggressively high.","solutions":["Obtain and submit a fresh, valid captcha token for the request","Check captcha service configuration (site key/secret) and that tokens match the site","Lower captchaScoreThreshold in configuration if legitimate users are rejected","Inspect captcha service logs/scores for the failing request to confirm cause"],"exampleFix":"// before\ncurl -X POST /v1/challenge -d '{\"captcha\":\"stale-token\"}'  -> 428\n// after\nrequest a new captcha, then\ncurl -X POST /v1/challenge -d '{\"captcha\":\"fresh-valid-token\"}'","handlingStrategy":"retry","validationCode":"if (captchaToken == null || captchaToken.isBlank()) {\n    throw new IllegalArgumentException(\"captcha token required\");\n}","typeGuard":null,"tryCatchPattern":"if (response.getStatus() == 428) { requestNewCaptchaAndRetry(); }","preventionTips":["Request a fresh captcha token for every challenge","Tune captchaScoreThreshold so legitimate users pass","Monitor 428 rates and captcha scores for config problems"],"tags":["http","security","captcha"],"backgroundTag":"http-error-response","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}