signalapp/Signal-Server · error · BraintreeException
result.getMessage()
Error message
result.getMessage()
What it means
BraintreeManager.createCustomer calls braintreeGateway.customer().create(request); when the Braintree gateway returns an unsuccessful Result (validation errors, declined, gateway problems), Signal wraps result.getMessage() in a BraintreeException. The message text is whatever Braintree's SDK reported, so the underlying cause is a rejected Braintree customer-creation request.
Solutions
- Inspect result.getMessage() / result.getErrors() in logs to get Braintree's specific validation error and fix the corresponding field.
- Verify Braintree gateway credentials (merchantId, publicKey, privateKey) and that environment matches the key set (SANDBOX vs PRODUCTION).
- If a duplicate customer id is being sent, generate a unique customer id or look up the existing customer first.
- Retry with backoff if Braintree reports a transient gateway/system error.
Example fix
// before
Result<Customer> result = braintreeGateway.customer().create(request);
if (!result.isSuccess()) {
throw new BraintreeException(result.getMessage());
}
// after: surface detailed errors
if (!result.isSuccess()) {
logger.warn("Braintree customer create failed: {}", result.getErrors().getAllDeepValidationErrors());
throw new BraintreeException(result.getMessage());
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify credentials and environment at startup braintreeGateway.clientToken().generate(); // fails fast on bad credentials/environment
Try / catch
try {
processorCustomer = braintreeManager.createCustomer(...);
} catch (BraintreeException e) {
log.warn("Braintree customer create failed: {}", e.getMessage());
showPaymentProviderUnavailable();
} Prevention
- Validate Braintree merchant credentials and environment (sandbox vs production) at deploy time
- Log result.getErrors() deep validation errors, not just getMessage()
- Generate unique customer ids to avoid duplicate-id errors
- Retry with backoff on transient Braintree gateway errors
When it happens
Trigger: braintreeGateway.customer().create(request) returns isSuccess() == false — e.g. invalid merchant credentials, processor/AVS validation errors, duplicate customer id, or Braintree API outage.
Common situations: Misconfigured Braintree environment (sandbox keys used against production or vice versa), expired/rotated API keys, invalid customer fields (bad id format, too-long custom fields), Braintree transient outage during signup.
Related errors
AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09).
Data as JSON: /api/errors/b7ae175d04354a09.
Report an issue: GitHub.
Appendix: source
Thrown at service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BraintreeManager.java:336
}
public record PayPalChargeSuccessDetails(String paymentId) {
}
@Override
public ProcessorCustomer createCustomer(final byte[] subscriberUser, @Nullable final ClientPlatform clientPlatform) {
final CustomerRequest request = new CustomerRequest()
.customField("subscriber_user", HexFormat.of().formatHex(subscriberUser));
if (clientPlatform != null) {
request.customField("client_platform", clientPlatform.name().toLowerCase());
}
final Result<Customer> result = braintreeGateway.customer().create(request);
if (!result.isSuccess()) {
throw new BraintreeException(result.getMessage());
}
return new ProcessorCustomer(result.getTarget().getId(), PaymentProvider.BRAINTREE);
}
@Override
public String createPaymentMethodSetupToken(final String customerId) {
final ClientTokenRequest request = new ClientTokenRequest().customerId(customerId);
return braintreeGateway.clientToken().generate(request);
}
@Override
public void setDefaultPaymentMethodForCustomer(final String customerId, final String billingAgreementToken,
@Nullable final String currentSubscriptionId) throws IOException {
final Optional<String> maybeSubscriptionId = Optional.ofNullable(currentSubscriptionId);
final TokenizePayPalBillingAgreementMutation.TokenizePayPalBillingAgreement tokenizePayPalBillingAgreement =
braintreeGraphqlClient.tokenizePayPalBillingAgreement(billingAgreementToken);
final VaultPaymentMethodMutation.VaultPaymentMethod vaultPaymentMethod =View on GitHub (pinned to 100ab61c82)