{"record":{"id":"e691a99f199bc23a","repo":"signalapp/Signal-Server","slug":"interrupted-during-delivery","errorCode":null,"errorMessage":"interrupted during delivery","messagePattern":"interrupted during delivery","errorType":"http","errorClass":"InternalServerErrorException","httpStatus":500,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java","lineNumber":652,"sourceCode":"    final MessageType messageType =\n        isStory ? MessageType.MULTI_RECIPIENT_STORY : MessageType.MULTI_RECIPIENT_SEALED_SENDER;\n\n    spamChecker.checkForMultiRecipientSpamHttp(messageType, context).response().ifPresent(response -> {\n      throw new WebApplicationException(response);\n    });\n\n    try {\n      if (!resolvedRecipients.isEmpty()) {\n        messageSender.sendMultiRecipientMessage(multiRecipientMessage,\n            resolvedRecipients,\n            timestamp, isStory,\n            ephemeral,\n            urgent,\n            context.getHeaderString(HttpHeaders.USER_AGENT)).get();\n      }\n    } catch (final InterruptedException e) {\n      logger.error(\"interrupted while delivering multi-recipient messages\", e);\n      throw new InternalServerErrorException(\"interrupted during delivery\");\n    } catch (final CancellationException e) {\n      logger.error(\"cancelled while delivering multi-recipient messages\", e);\n      throw new InternalServerErrorException(\"delivery cancelled\");\n    } catch (final ExecutionException e) {\n      logger.error(\"partial failure while delivering multi-recipient messages\", e.getCause());\n      throw new InternalServerErrorException(\"failure during delivery\");\n    } catch (final MessageTooLargeException e) {\n      throw new WebApplicationException(Status.REQUEST_ENTITY_TOO_LARGE);\n    } catch (final MultiRecipientMismatchedDevicesException e) {\n      final List<AccountMismatchedDevices> accountMismatchedDevices =\n          e.getMismatchedDevicesByServiceIdentifier().entrySet().stream()\n              .filter(entry -> !entry.getValue().missingDeviceIds().isEmpty() || !entry.getValue().extraDeviceIds().isEmpty())\n              .map(entry -> new AccountMismatchedDevices(entry.getKey(),\n                  new MismatchedDevicesResponse(entry.getValue().missingDeviceIds(), entry.getValue().extraDeviceIds())))\n              .toList();\n\n      if (!accountMismatchedDevices.isEmpty()) {\n        throw new WebApplicationException(Response","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java#L634-L670","documentation":"Thrown as HTTP 500 when the executor thread delivering multi-recipient messages is interrupted while the server waits on the futures of per-recipient deliveries. The server logs the interruption and converts it into an InternalServerErrorException.","triggerScenarios":"Thread interruption (e.g. server shutdown, request timeout canceling the worker) while sendMultiRecipientMessage blocks on Future.get() for the batch of recipient deliveries.","commonSituations":"Graceful shutdown or load-balancer timeout cutting off a large multi-recipient story send; executor shutdown mid-flight.","solutions":["Retry the send; it is a transient server-side interruption","If the client caused the timeout, increase the client HTTP timeout for multi-recipient sends","Check server logs for shutdown/interruption cause and reduce batch size if frequently hit"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await sendMultiRecipientMessage(msg); } catch (e) { if (e.status === 500 && /interrupted/.test(e.message)) await withBackoff(() => send(msg)); else throw e; }","preventionTips":["Retry idempotent multi-recipient sends with backoff","Set generous client timeouts for large fan-out sends","Avoid triggering sends right at server maintenance windows"],"tags":["http-500","interruption","concurrency","signal-server"],"backgroundTag":"request-timeout","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"}