signalapp/Signal-Server · error · BackupWrongCredentialTypeException

wrong credential type for the requested operation

Error message

wrong credential type for the requested operation

What it means

BackupWrongCredentialTypeException thrown by BackupManager.checkBackupCredentialType when the AuthenticatedBackupUser's credential type (MEDIA or MESSAGES) differs from the type the operation requires. Backup credentials are scoped: media operations demand MEDIA credentials and message-backup operations demand MESSAGES credentials. A 'credential_type' authorization-failure counter is incremented.

Solutions

  1. Authenticate separately for each credential type and use the MEDIA credential for media endpoints and MESSAGES for message-backup endpoints
  2. Store credentials keyed by BackupCredentialType instead of a single cached token
  3. Check backupUser.credentialType() before issuing the request and switch credentials if needed
  4. Update clients that predate credential-type separation

Example fix

// before
authenticate(messagesCredential);
copyMedia(...); // wrong credential type for the requested operation
// after
authenticate(mediaCredential);
copyMedia(...);
Defensive patterns

Strategy: validation

Validate before calling

if (backupUser.credentialType() != BackupCredentialType.MEDIA) {
  throw new IllegalStateException("media endpoint requires a MEDIA credential");
}

Try / catch

try { copyMedia(backupUser, toCopy); }
catch (BackupWrongCredentialTypeException e) {
  backupUser = authenticateForType(BackupCredentialType.MEDIA);
  copyMedia(backupUser, toCopy); // re-authenticate with correct type and retry once
}

Prevention

When it happens

Trigger: Calling a MEDIA-gated endpoint (e.g. media copy/quota, cdn read auth) while authenticated with a MESSAGES credential, or vice versa — typically after authenticating against the wrong backup-auth endpoint for the operation being attempted.

Common situations: Client caching one backup auth result and reusing it across both media and message-backup flows; MESSAGES (SVRB) flows accidentally invoking media upload helpers; refactors that swap the credential type used to authenticate; older clients where types were not separated.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java:801

    }
  }

  /**
   * Check that the authenticated backup user is authenticated with the given credential type
   *
   * @param backupUser     The backup user to check
   * @param credentialType The credential type to require
   * @throws BackupWrongCredentialTypeException error if the backup user is not authenticated with the given
   * {@code credentialType}
   */
  @VisibleForTesting
  static void checkBackupCredentialType(final AuthenticatedBackupUser backupUser, final BackupCredentialType credentialType) throws BackupWrongCredentialTypeException {
    if (backupUser.credentialType() != credentialType) {
      Metrics.counter(ZK_AUTHZ_FAILURE_COUNTER_NAME,
              FAILURE_REASON_TAG_NAME, "credential_type")
          .increment();

      throw new BackupWrongCredentialTypeException("wrong credential type for the requested operation");
    }
  }

  @VisibleForTesting
  static String encodeMediaIdForCdn(final byte[] bytes) {
    return Base64.getUrlEncoder().encodeToString(bytes);
  }

  private static byte[] decodeMediaIdFromCdn(final String base64) {
    return Base64.getUrlDecoder().decode(base64);
  }

  private static String cdnMessageBackupName(final AuthenticatedBackupUser backupUser) {
    return "%s/%s".formatted(backupUser.backupDir(), MESSAGE_BACKUP_NAME);
  }

  private static String cdnMediaDirectory(final String backupDir, final String mediaDir) {
    return "%s/%s/".formatted(backupDir, mediaDir);

View on GitHub (pinned to 100ab61c82)