{"record":{"id":"8848071713bed880","repo":"signalapp/Signal-Server","slug":"500-internal-server-error-registration-service-fa","errorCode":null,"errorMessage":"500 Internal Server Error (registration service failure)","messagePattern":"500 Internal Server Error \\(registration service failure\\)","errorType":"http","errorClass":"ServerErrorException","httpStatus":500,"severity":"critical","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/VerificationController.java","lineNumber":664,"sourceCode":"          .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())\n        .filter(existingAccount ->\n            experimentEnrollmentManager.isEnrolled(existingAccount.getAccountIdentifier(), VERIFICATION_CODE_PUSH_NOTIFICATION_EXPERIMENT_NAME))\n        .ifPresent(existingAccount -> {\n          try {\n            pushNotificationManager.sendVerificationCodeRequestedNotifications(existingAccount, clock.instant());\n          } catch (final NotPushRegisteredException _) {\n          }\n        });\n\n    Metrics.counter(CODE_REQUESTED_COUNTER_NAME, Tags.of(\n            UserAgentTagUtil.getPlatformTag(userAgent),\n            Tag.of(COUNTRY_CODE_TAG_NAME, Util.getCountryCode(registrationServiceSession.number())),\n            Tag.of(REGION_CODE_TAG_NAME, Util.getRegion(registrationServiceSession.number())),\n            Tag.of(VERIFICATION_TRANSPORT_TAG_NAME, verificationCodeRequest.transport().toString())))\n        .increment();","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/VerificationController.java#L646-L682","documentation":"A 500 Internal Server Error thrown by the verification controller when the registration service client throws an unexpected RuntimeException during verification-code request/creation. The controller logs 'Registration service failure' and maps it to ServerErrorException(500). It signals an unexpected downstream failure, not a client mistake.","triggerScenarios":"Calling POST /v1/verification/session/{id}/code (requestVerificationCode) when the call into registrationServiceClient (e.g. sendVerificationCode) fails with a RuntimeException such as a gRPC transport error wrapped outside the expected checked exceptions.","commonSituations":"Registration service down or network partition between Signal server and registration service; gRPC channel closed; misconfigured registration service URI in config; DNS failures in a Kubernetes cluster after service rename.","solutions":["Check server logs for the 'Registration service failure' stack trace to find the root cause","Verify the registration service is reachable (network policy, DNS, port)","Confirm registration service config values (host, port, TLS) in the server YAML","Retry the request after the registration service recovers; the client may also retry at the gRPC level"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// client-side health probe before calling\nconst healthy = await fetch(REGISTRATION_HEALTH_URL).then(r => r.ok).catch(() => false);\nif (!healthy) throw new Error('registration service unavailable, retry later');","typeGuard":null,"tryCatchPattern":"try {\n  await requestVerificationCode(sessionId, channel);\n} catch (e) {\n  if (e.status === 500) scheduleRetryWithBackoff(e); // transient server-side failure\n  else throw e;\n}","preventionTips":["Monitor registration service health and alert on 5xx spikes","Configure gRPC retries for UNAVAILABLE statuses","Keep registration service endpoint config validated at server startup"],"tags":["http-500","grpc","registration-service","server-error"],"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"}