signalapp/Signal-Server · error · WebApplicationException
Invalid combined unidentified sender access keys
Error message
Invalid combined unidentified sender access keys
What it means
CombinedUnidentifiedSenderAccessKeys parses a header of Base64-encoded combined unidentified sender access keys and throws WebApplicationException(401) if decoding fails (IllegalArgumentException) or the decoded array is null / not 16 bytes. The combined keys value must be exactly 16 bytes like a single access key (the XOR combination).
Solutions
- Compute the combined key as the protocol-specified 16-byte combination (XOR) of the sender's key and the recipient's unrestricted access key, not a concatenation
- Verify the decoded length is 16 before sending
- Re-derive from current identity keys if accounts re-registered
Example fix
// before byte[] combined = concat(senderAccessKey, recipientAccessKey); // 32 bytes // after byte[] combined = new byte[16]; for (int i = 0; i < 16; i++) combined[i] = (byte)(senderAccessKey[i] ^ recipientAccessKey[i]);
Defensive patterns
Strategy: validation
Validate before calling
byte[] combined = Base64.getDecoder().decode(header);
if (combined == null || combined.length != 16) throw new IllegalArgumentException("combined access keys must decode to 16 bytes"); Try / catch
try { authFilter.call(); } catch (WebApplicationException e) { if (e.getResponse().getStatus() == 401) { /* recompute combined key */ } } Prevention
- XOR-combine to 16 bytes; never concatenate access keys
- Recompute after either party re-registers
- Test decode length before sending
When it happens
Trigger: Supplying a header whose Base64 decodes to a non-16-byte array; malformed Base64 (caught as IllegalArgumentException and wrapped with the same message context); sending per-recipient multi-byte concatenations instead of the 16-byte combined value.
Common situations: Client computes the combined key incorrectly (e.g. concatenates both 16-byte keys yielding 32 bytes); wrong Base64 alphabet or padding; stale key material after re-registration.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- access key length must be 16
- Missing credentials
- A group send endorsement token or unidentified access key…
- Multi-recipient messages must be addressed to ACI service…
- 400 Bad Request (invalid ProfileKeyCommitment base64)
AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09).
Data as JSON: /api/errors/d1ba3eb89be6bbe4.
Report an issue: GitHub.
Appendix: source
Thrown at service/src/main/java/org/whispersystems/textsecuregcm/auth/CombinedUnidentifiedSenderAccessKeys.java:20
* Copyright 2021 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.auth;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import java.util.Base64;
public class CombinedUnidentifiedSenderAccessKeys {
private final byte[] combinedUnidentifiedSenderAccessKeys;
public CombinedUnidentifiedSenderAccessKeys(String header) {
try {
this.combinedUnidentifiedSenderAccessKeys = Base64.getDecoder().decode(header);
if (this.combinedUnidentifiedSenderAccessKeys == null || this.combinedUnidentifiedSenderAccessKeys.length != UnidentifiedAccessUtil.UNIDENTIFIED_ACCESS_KEY_LENGTH) {
throw new WebApplicationException("Invalid combined unidentified sender access keys", Status.UNAUTHORIZED);
}
} catch (IllegalArgumentException e) {
throw new WebApplicationException(e, Response.Status.UNAUTHORIZED);
}
}
public byte[] getAccessKeys() {
return combinedUnidentifiedSenderAccessKeys;
}
}
View on GitHub (pinned to 100ab61c82)