signalapp/Signal-Server · error · WebApplicationException

access key length must be 16

Error message

access key length must be 16

What it means

Anonymous is a JAX-RS auth provider wrapper for unidentified-delivery access keys. It Base64-decodes the X-Signal-Access-Key header and rejects it with HTTP 401 unless the decoded byte array is exactly UnidentifiedAccessUtil.UNIDENTIFIED_ACCESS_KEY_LENGTH (16) bytes. This prevents calls to profiles/messages from using malformed access keys.

Solutions

  1. Ensure the header is Base64 of the account's 16-byte unidentified access key (UUID-derived, per Signal protocol)
  2. Decode your Base64 client-side and assert the array length is 16 before sending
  3. Regenerate the access key from the correct account identity key material if it is stale or misderived

Example fix

// before
String header = Base64.getEncoder().encodeToString(uuid.toString().getBytes());
// after
byte[] key = UnidentifiedAccessUtil.getAccessKeyFor(acdUuid, identityKey);
String header = Base64.getEncoder().encodeToString(key); // 16 bytes
Defensive patterns

Strategy: validation

Validate before calling

byte[] key = Base64.getDecoder().decode(header);
if (key.length != 16) throw new IllegalArgumentException("access key must be 16 bytes, got " + key.length);

Try / catch

try { authFilter.call(); } catch (WebApplicationException e) { if (e.getResponse().getStatus() == 401) { /* regenerate access key and retry once */ } }

Prevention

When it happens

Trigger: Sending a request with an access-key header whose Base64 value decodes to a byte array that is not 16 bytes long (e.g. 0 bytes, 8, 32 bytes).

Common situations: Clients building the header from a raw string instead of the account's 16-byte unidentified access key; double/truncated Base64 encoding; sending an empty header value that Base64-decodes to an empty array; old clients after a key-length change.

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


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

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/auth/Anonymous.java:20

 * Copyright 2013-2020 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 java.util.Base64;

public class Anonymous {

  private final byte[] unidentifiedSenderAccessKey;

  public Anonymous(String header) {
    try {
      this.unidentifiedSenderAccessKey = Base64.getDecoder().decode(header);
      if (unidentifiedSenderAccessKey.length != UnidentifiedAccessUtil.UNIDENTIFIED_ACCESS_KEY_LENGTH) {
        throw new WebApplicationException("access key length must be 16", Response.Status.UNAUTHORIZED);
      }
    } catch (IllegalArgumentException e) {
      throw new WebApplicationException(e, Response.Status.UNAUTHORIZED);
    }
  }

  public byte[] getAccessKey() {
    return unidentifiedSenderAccessKey;
  }
}

View on GitHub (pinned to 100ab61c82)