{"record":{"id":"786b439998973b10","repo":"signalapp/Signal-Server","slug":"received-bad-envelope-type-from","errorCode":null,"errorMessage":"Received bad envelope type {} from {}","messagePattern":"Received bad envelope type (.+?) from (.+?)","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java","lineNumber":394,"sourceCode":"      messageByteLimitEstimator.add(destinationIdentifier.uuid().toString());\n      throw e;\n    }\n\n    final Map<Byte, Envelope> messagesByDeviceId = messages.messages().stream()\n        .collect(Collectors.toMap(IncomingMessage::destinationDeviceId, message -> {\n          try {\n            return message.toEnvelope(\n                destinationIdentifier,\n                sender != null ? new AciServiceIdentifier(sender.accountIdentifier()) : null,\n                sender != null ? sender.deviceId() : null,\n                messages.timestamp() == 0 ? System.currentTimeMillis() : messages.timestamp(),\n                isStory,\n                messages.online(),\n                messages.urgent(),\n                spamCheckResult.token().orElse(null),\n                clock);\n          } catch (final IllegalArgumentException e) {\n            logger.warn(\"Received bad envelope type {} from {}\", message.type(), userAgent);\n            throw new BadRequestException(e);\n          }\n        }));\n\n    final Map<Byte, Integer> registrationIdsByDeviceId = messages.messages().stream()\n        .collect(Collectors.toMap(IncomingMessage::destinationDeviceId, IncomingMessage::destinationRegistrationId));\n\n    final Optional<Byte> syncMessageSenderDeviceId = messageType == MessageType.SYNC\n        ? Optional.ofNullable(sender).map(AuthenticatedDevice::deviceId)\n        : Optional.empty();\n\n    try {\n      messageSender.sendMessages(destination,\n          destinationIdentifier,\n          messagesByDeviceId,\n          registrationIdsByDeviceId,\n          syncMessageSenderDeviceId,\n          userAgent);","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java#L376-L412","documentation":"The message controller validates the envelope type byte on each incoming message before enqueueing it. If the client-supplied Envelope.Type value cannot be constructed (an unknown/invalid enum ordinal), an IllegalArgumentException is logged with the type value and user agent, and a 400 Bad Request is returned to the sender. This protects the queue from persisting envelopes that cannot be deserialized by recipients.","triggerScenarios":"A client POSTs to /v1/messages (or the sealed sender / sync / story variants) with a message whose `type` field is a byte not corresponding to a known Envelope.Type enum constant.","commonSituations":"Outdated or third-party client libraries sending newer or garbage type bytes; protocol drift between client and server versions; corrupted or hand-crafted payloads during testing.","solutions":["Update the client library/SDK to a version whose Envelope.Type enum matches the server's supported types.","Check the logged type value and user agent to identify which client is sending invalid types.","Validate message.type() client-side against the known enum range before sending.","If this is a legitimate new type, deploy server support for the new Envelope.Type first."],"exampleFix":"// before: sending a raw type byte from the client\nmessageBuilder.setType(unknownTypeByte);\n\n// after: constrain to the known enum\nmessageBuilder.setType(Envelope.Type.forName(typeString)); // or a validated constant","handlingStrategy":"validation","validationCode":"// client-side, before sending\nif (Envelope.Type.forNumber(typeByte) == null) {\n  throw new IllegalArgumentException(\"Unsupported envelope type: \" + typeByte);\n}","typeGuard":"boolean isKnownEnvelopeType(byte t) { return Envelope.Type.forNumber(t) != null && Envelope.Type.forNumber(t) != Envelope.Type.UNRECOGNIZED; }","tryCatchPattern":"try {\n  sendMessage(message);\n} catch (BadRequestException e) {\n  logger.warn(\"server rejected envelope type {}\", message.getType());\n}","preventionTips":["Keep client and server proto/enum definitions in sync (same Envelope.Type set).","Never send raw unvalidated type bytes; always construct types from the generated enum.","Pin third-party client library versions known to match the server protocol version."],"tags":["protobuf","enum","bad-request","validation"],"backgroundTag":"invalid-enum-value","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"}