{"record":{"id":"96e6b49bf10a4a15","repo":"signalapp/Signal-Server","slug":"use-websockets","errorCode":null,"errorMessage":"use websockets","messagePattern":"use websockets","errorType":"http","errorClass":"WebApplicationException","httpStatus":498,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilter.java","lineNumber":81,"sourceCode":"\n    final String userAgentString = requestContext.getHeaderString(HttpHeaders.USER_AGENT);\n\n    try {\n      final UserAgent userAgent = UserAgentUtil.parseUserAgentString(userAgentString);\n      final ClientPlatform platform = userAgent.platform();\n      final Semver version = userAgent.version();\n      final PlatformConfiguration config = dynamicConfigurationManager.getConfiguration().restDeprecation().platforms().get(platform);\n      if (config == null) {\n        return;\n      }\n      if (!isEnrolled(requestContext, config.universalRolloutPercent())) {\n        return;\n      }\n      if (version.isGreaterThanOrEqualTo(config.minimumRestFreeVersion())) {\n        Metrics.counter(\n            DEPRECATED_REST_COUNTER_NAME, Tags.of(\"platform\", platform.name().toLowerCase(), \"version\", version.toString()))\n            .increment();\n        throw new WebApplicationException(\"use websockets\", 498);\n      }\n    } catch (final UnrecognizedUserAgentException e) {\n      return;                   // at present we're only interested in experimenting on known clients\n    }\n  }\n\n  private boolean isEnrolled(final ContainerRequestContext requestContext, int universalRolloutPercent) {\n    if (random.get().nextInt(100) < universalRolloutPercent) {\n      return true;\n    }\n\n    final SecurityContext securityContext = requestContext.getSecurityContext();\n\n    if (securityContext == null || securityContext.getUserPrincipal() == null) {\n      return false;\n    }\n\n    if (securityContext.getUserPrincipal() instanceof AuthenticatedDevice authenticatedDevice) {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/filters/RestDeprecationFilter.java#L63-L99","documentation":"RestDeprecationFilter rejects REST API calls from clients whose reported version is at or above the minimumRestFreeVersion, pushing them to the Signal websocket transport. It throws WebApplicationException with custom status 498 and message 'use websockets', while incrementing a metrics counter tagged by platform and version. Unknown user agents are ignored (allowed through).","triggerScenarios":"Any REST request whose User-Agent is a recognized platform with a parsed version >= minimumRestFreeVersion configured in RestDeprecationConfiguration; unauthenticated and authenticated requests both blocked.","commonSituations":"Older Signal-Android/iOS releases after the server enables REST deprecation; third-party clients (e.g. signal-cli, libraries) that still use REST endpoints; local tools using outdated API clients.","solutions":["Upgrade the client library/app to a version that uses the websocket transport","If you maintain a third-party client, implement the WebSocket-based signaling protocol","If operating the server, raise (or disable) minimumRestFreeVersion in RestDeprecationConfiguration to allow older clients temporarily"],"exampleFix":"// before (config)\nminimumRestFreeVersion: 710\n// after (temporarily allow old clients)\nminimumRestFreeVersion: 999999","handlingStrategy":"validation","validationCode":"String ua = \"Signal-Android/7.10.2\";\nif (UserAgentUtil.parseUserAgentString(ua).map(p -> p.version().compareTo(minimumRestFreeVersion) >= 0).orElse(false)) {\n  throw new UnsupportedOperationException(\"REST deprecated for this version; use websockets\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  restClient.sendMessage(message);\n} catch (WebApplicationException e) {\n  if (e.getResponse().getStatus() == 498) {\n    // fall back to websocket transport\n  }\n}","preventionTips":["Keep Signal clients updated so they use websocket transport","Check the server's RestDeprecationConfiguration when building third-party clients","Watch for HTTP 498 as a signal to migrate off REST"],"tags":["rest","websocket","deprecation","user-agent","http-client"],"backgroundTag":"deprecated-api-usage","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"}