{"record":{"id":"1af7a305de093b89","repo":"signalapp/Signal-Server","slug":"response-status-418-entity-verificationsessionr","errorCode":null,"errorMessage":"? Response.status(418).entity(verificationSessionResponse).build()","messagePattern":"\\? Response\\.status\\(418\\)\\.entity\\(verificationSessionResponse\\)\\.build\\(\\)","errorType":"http","errorClass":"ClientErrorException","httpStatus":418,"severity":"warning","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/VerificationController.java","lineNumber":649,"sourceCode":"\n    final RegistrationServiceSession resultSession;\n    try {\n      resultSession = registrationServiceClient.sendVerificationCode(registrationServiceSession.id(),\n          messageTransport,\n          clientType,\n          acceptLanguage.orElse(null),\n          senderOverride,\n          REGISTRATION_RPC_TIMEOUT);\n    } catch (final VerificationSessionRateLimitExceededException e) {\n      throw new ClientErrorException(buildResponseForRateLimitExceeded(verificationSession,\n          e.getRegistrationSession(),\n          e.getRetryDuration()));\n    } catch (final RegistrationServiceException registrationServiceException) {\n      throw registrationServiceException.getRegistrationSession()\n          .map(s -> buildResponse(s, verificationSession))\n          .map(verificationSessionResponse -> {\n            final Response response = registrationServiceException instanceof TransportNotAllowedException\n                ? Response.status(418).entity(verificationSessionResponse).build()\n                : Response.status(Response.Status.CONFLICT).entity(verificationSessionResponse).build();\n\n            return new ClientErrorException(response);\n          })\n          .orElseGet(NotFoundException::new);\n    } catch (final RegistrationFraudException e) {\n      if (dynamicConfigurationManager.getConfiguration().getRegistrationConfiguration()\n          .squashDeclinedAttemptErrors()) {\n        return buildResponse(registrationServiceSession, verificationSession);\n      } else {\n        throw e.getCause();\n      }\n    } catch (final RuntimeException e) {\n      logger.error(\"Registration service failure\", e);\n      throw new ServerErrorException(Response.Status.INTERNAL_SERVER_ERROR);\n    }\n\n    accountsManager.getByE164(registrationServiceSession.number())","sourceCodeStart":631,"sourceCodeEnd":667,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/VerificationController.java#L631-L667","documentation":"requestVerificationCode returns HTTP 418 (\"I'm a teapot\", Signal's convention for transport-not-allowed) when the registration service rejects the requested verification transport (e.g. voice call or SMS) for this session/number. If the exception carries a registration session, the client gets a 418 (TransportNotAllowedException) or 409 (other RegistrationServiceException) with an updated VerificationSessionResponse body; otherwise it gets 404.","triggerScenarios":"POST/PUT to request a verification code where the registration service refuses the chosen channel — e.g. requesting SMS for a number flagged to only allow voice, or a transport blocked by fraud detection for that session.","commonSituations":"Numbers in regions where SMS delivery is disabled/blocked; carriers/routes flagged by fraud prevention; clients retrying the same disallowed transport in a loop instead of switching channel or completing an existing session.","solutions":["Switch to a different transport (e.g. request a voice call instead of SMS) for this session","Use the returned verificationSessionResponse to continue the existing session rather than starting a new request","Wait and retry later if the transport is temporarily blocked by fraud rules","Check registration-service configuration/allow-lists if a region should permit the transport"],"exampleFix":"// before: retry same transport forever\nrequestCode(phoneNumber, Transport.SMS);\n// after\nif (response.code() == 418) {\n  updateSessionFromResponse(response.body());\n  requestCode(phoneNumber, Transport.VOICE); // try alternate transport\n}","handlingStrategy":"try-catch","validationCode":"// check whether the session allows the requested transport first\nif (!session.getAllowedTransports().contains(requestedTransport)) {\n  requestedTransport = session.getAllowedTransports().iterator().next();\n}","typeGuard":null,"tryCatchPattern":"try { requestVerificationCode(session, transport); }\ncatch (ClientErrorException e) {\n  if (e.getResponse().getStatus() == 418) {\n    updateSession(e.getResponse().readEntity(VerificationSessionResponse.class));\n    switchTransportAndRetry();\n  }\n}","preventionTips":["Advertise/surface allowed transports from the session state","Never retry the same disallowed transport in a loop","Resume the existing session using the returned session response","Watch fraud-rule feedback (418) and back off rather than escalating"],"tags":["http","verification","sms","registration"],"backgroundTag":"unexpected-http-status","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"}