{"record":{"id":"5b380c165c7b0ab7","repo":"signalapp/Signal-Server","slug":"wrong-credential-type-for-the-requested-operation","errorCode":null,"errorMessage":"wrong credential type for the requested operation","messagePattern":"wrong credential type for the requested operation","errorType":"exception","errorClass":"BackupWrongCredentialTypeException","httpStatus":403,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java","lineNumber":801,"sourceCode":"    }\n  }\n\n  /**\n   * Check that the authenticated backup user is authenticated with the given credential type\n   *\n   * @param backupUser     The backup user to check\n   * @param credentialType The credential type to require\n   * @throws BackupWrongCredentialTypeException error if the backup user is not authenticated with the given\n   * {@code credentialType}\n   */\n  @VisibleForTesting\n  static void checkBackupCredentialType(final AuthenticatedBackupUser backupUser, final BackupCredentialType credentialType) throws BackupWrongCredentialTypeException {\n    if (backupUser.credentialType() != credentialType) {\n      Metrics.counter(ZK_AUTHZ_FAILURE_COUNTER_NAME,\n              FAILURE_REASON_TAG_NAME, \"credential_type\")\n          .increment();\n\n      throw new BackupWrongCredentialTypeException(\"wrong credential type for the requested operation\");\n    }\n  }\n\n  @VisibleForTesting\n  static String encodeMediaIdForCdn(final byte[] bytes) {\n    return Base64.getUrlEncoder().encodeToString(bytes);\n  }\n\n  private static byte[] decodeMediaIdFromCdn(final String base64) {\n    return Base64.getUrlDecoder().decode(base64);\n  }\n\n  private static String cdnMessageBackupName(final AuthenticatedBackupUser backupUser) {\n    return \"%s/%s\".formatted(backupUser.backupDir(), MESSAGE_BACKUP_NAME);\n  }\n\n  private static String cdnMediaDirectory(final String backupDir, final String mediaDir) {\n    return \"%s/%s/\".formatted(backupDir, mediaDir);","sourceCodeStart":783,"sourceCodeEnd":819,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java#L783-L819","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Authenticate separately for each credential type and use the MEDIA credential for media endpoints and MESSAGES for message-backup endpoints","Store credentials keyed by BackupCredentialType instead of a single cached token","Check backupUser.credentialType() before issuing the request and switch credentials if needed","Update clients that predate credential-type separation"],"exampleFix":"// before\nauthenticate(messagesCredential);\ncopyMedia(...); // wrong credential type for the requested operation\n// after\nauthenticate(mediaCredential);\ncopyMedia(...);","handlingStrategy":"validation","validationCode":"if (backupUser.credentialType() != BackupCredentialType.MEDIA) {\n  throw new IllegalStateException(\"media endpoint requires a MEDIA credential\");\n}","typeGuard":null,"tryCatchPattern":"try { copyMedia(backupUser, toCopy); }\ncatch (BackupWrongCredentialTypeException e) {\n  backupUser = authenticateForType(BackupCredentialType.MEDIA);\n  copyMedia(backupUser, toCopy); // re-authenticate with correct type and retry once\n}","preventionTips":["Key cached backup credentials by BackupCredentialType","Authenticate through the endpoint matching the operation's credential type","Assert credential type at the boundary of each media/messages flow","Update clients predating MEDIA/MESSAGES credential separation"],"tags":["backup","credential-type","authorization"],"backgroundTag":"type-mismatch","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"}