{"record":{"id":"f457306e970e82fe","repo":"signalapp/Signal-Server","slug":"unrecognized-level","errorCode":null,"errorMessage":"unrecognized level","messagePattern":"unrecognized level","errorType":"exception","errorClass":"InvalidLevelException","httpStatus":null,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/grpc/OneTimeDonationUtil.java","lineNumber":112,"sourceCode":"    // item name will not match. We could try to align with the locales PayPal documents <https://developer.paypal.com/reference/locale-codes/#supported-locale-codes>\n    // but that's a moving target, and we can hopefully have one of them be better for the user by selecting\n    // independently.\n    final Locale locale = SubscriptionsUtil.getPayPalLocale(acceptableLocales);\n    final String localizedLineItemName = payPalDonationsTranslator.translate(acceptableLocales,\n        org.whispersystems.textsecuregcm.subscriptions.PayPalDonationsTranslator.ONE_TIME_DONATION_LINE_ITEM_KEY);\n    return new LocalizedPayPalDonationLineItem(locale, localizedLineItemName);\n  }\n\n  public static DonationLevelDetails getLevelDetails(final PaymentDetails paymentDetails,\n      final OneTimeDonationConfiguration oneTimeDonationConfiguration)\n      throws InvalidLevelException {\n\n    final Duration levelExpiration = switch (paymentDetails.level()) {\n      case ONE_TIME_DONATION -> oneTimeDonationConfiguration.boost().expiration();\n      case ONE_TIME_GIFT_DONATION -> oneTimeDonationConfiguration.gift().expiration();\n      default -> {\n        LOGGER.error(\"level ({}) returned from payment intent that is unknown to the server\", paymentDetails.level());\n        throw new InvalidLevelException(\"unrecognized level\");\n      }\n    };\n    return new DonationLevelDetails(paymentDetails.level(), levelExpiration);\n  }\n\n}\n","sourceCodeStart":94,"sourceCodeEnd":119,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/grpc/OneTimeDonationUtil.java#L94-L119","documentation":"OneTimeDonationUtil.getLevelDetails maps a Stripe payment-intent metadata 'level' to a donation expiration duration. If the level from the payment intent is not ONE_TIME_DONATION or ONE_TIME_GIFT_DONATION, it logs the unknown level and throws InvalidLevelException('unrecognized level').","triggerScenarios":"Processing a completed Stripe payment intent whose 'level' metadata value is missing, misspelled, or was set by an older/newer checkout flow that defines donation levels the server build doesn't recognize.","commonSituations":"Server deploy lagging behind a checkout page that added a new donation level; Stripe dashboard manual test payments lacking metadata; stale configuration of one-time donation levels after a rename.","solutions":["Verify the Stripe payment intent metadata 'level' matches a DonationLevel enum value known to the server","Redeploy/update the server to a build that includes the new donation level","Correct the checkout/donation configuration so it only produces supported levels","Manually fix the level metadata on the affected payment intent and retry processing"],"exampleFix":"// before (checkout metadata)\n\"level\": \"boost_champion\"\n// after\n\"level\": \"ONE_TIME_DONATION\"","handlingStrategy":"try-catch","validationCode":"try {\n  DonationLevel.valueOf(levelString);\n} catch (IllegalArgumentException e) {\n  throw new IllegalArgumentException(\"unsupported donation level: \" + levelString);\n}","typeGuard":"static boolean isKnownLevel(String level) {\n  for (DonationLevel l : DonationLevel.values()) {\n    if (l.name().equals(level)) return true;\n  }\n  return false;\n}","tryCatchPattern":"try {\n  processPayment(paymentIntent);\n} catch (InvalidLevelException e) {\n  LOGGER.warn(\"Skipping payment intent {} with unknown level\", paymentIntent.id());\n}","preventionTips":["Keep the checkout page's level metadata in sync with DonationLevel enum values","Add integration tests covering every donation level the checkout can emit","Monitor the 'level unknown' server log for drift between checkout and server"],"tags":["stripe","donations","enum","payment-processing"],"backgroundTag":"invalid-enum-value","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}