signalapp/Signal-Server · warning · BadRequestException

Received bad envelope type

Error message

Received bad envelope type {} from {}

What it means

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.

Solutions

  1. Update the client library/SDK to a version whose Envelope.Type enum matches the server's supported types.
  2. Check the logged type value and user agent to identify which client is sending invalid types.
  3. Validate message.type() client-side against the known enum range before sending.
  4. If this is a legitimate new type, deploy server support for the new Envelope.Type first.

Example fix

// before: sending a raw type byte from the client
messageBuilder.setType(unknownTypeByte);

// after: constrain to the known enum
messageBuilder.setType(Envelope.Type.forName(typeString)); // or a validated constant
Defensive patterns

Strategy: validation

Validate before calling

// client-side, before sending
if (Envelope.Type.forNumber(typeByte) == null) {
  throw new IllegalArgumentException("Unsupported envelope type: " + typeByte);
}

Type guard

boolean isKnownEnvelopeType(byte t) { return Envelope.Type.forNumber(t) != null && Envelope.Type.forNumber(t) != Envelope.Type.UNRECOGNIZED; }

Try / catch

try {
  sendMessage(message);
} catch (BadRequestException e) {
  logger.warn("server rejected envelope type {}", message.getType());
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/786b439998973b10. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java:394

      messageByteLimitEstimator.add(destinationIdentifier.uuid().toString());
      throw e;
    }

    final Map<Byte, Envelope> messagesByDeviceId = messages.messages().stream()
        .collect(Collectors.toMap(IncomingMessage::destinationDeviceId, message -> {
          try {
            return message.toEnvelope(
                destinationIdentifier,
                sender != null ? new AciServiceIdentifier(sender.accountIdentifier()) : null,
                sender != null ? sender.deviceId() : null,
                messages.timestamp() == 0 ? System.currentTimeMillis() : messages.timestamp(),
                isStory,
                messages.online(),
                messages.urgent(),
                spamCheckResult.token().orElse(null),
                clock);
          } catch (final IllegalArgumentException e) {
            logger.warn("Received bad envelope type {} from {}", message.type(), userAgent);
            throw new BadRequestException(e);
          }
        }));

    final Map<Byte, Integer> registrationIdsByDeviceId = messages.messages().stream()
        .collect(Collectors.toMap(IncomingMessage::destinationDeviceId, IncomingMessage::destinationRegistrationId));

    final Optional<Byte> syncMessageSenderDeviceId = messageType == MessageType.SYNC
        ? Optional.ofNullable(sender).map(AuthenticatedDevice::deviceId)
        : Optional.empty();

    try {
      messageSender.sendMessages(destination,
          destinationIdentifier,
          messagesByDeviceId,
          registrationIdsByDeviceId,
          syncMessageSenderDeviceId,
          userAgent);

View on GitHub (pinned to 100ab61c82)