Handle Errors from the Mercado Pago Java SDK Clients
Understand MPException and MPApiException, inspect API error responses, handle specific status codes, and implement robust retry and idempotency logic.
Use this file to discover all available pages before exploring further.
The Mercado Pago Java SDK uses a two-level exception hierarchy to distinguish between problems that occurred before the API could respond and problems reported by the API itself. Understanding which exception you are dealing with — and what data it carries — lets you write precise error-handling logic: retrying transient network blips, surfacing actionable validation errors to users, and alerting on unexpected server faults. This guide covers both exception types in detail, common HTTP status codes, idempotency keys, retry configuration, and pagination with MPSearchRequest.
MPException (and its subclasses) is thrown when something goes wrong before the API responds or while processing the response — for example, a network timeout, a DNS resolution failure, or a failure to serialize your request object to JSON. These errors are not caused by your request data; they reflect environmental or SDK-internal issues.Key methods inherited from Exception:
Method
Description
getMessage()
Human-readable description of the failure.
getCause()
The underlying Throwable that triggered this exception, if any.
MPApiException is thrown when the SDK successfully communicates with the Mercado Pago API but the API returns a non-2xx HTTP status code (4xx or 5xx). It always carries the raw API response so you can inspect the error body for details.Key methods:
Method
Return type
Description
getStatusCode()
int
HTTP status code returned by the API (e.g., 400, 401, 404).
getApiResponse()
MPResponse
Full response object with headers and body.
getApiResponse().getContent()
String
Raw JSON body of the error response.
getApiResponse().getStatusCode()
Integer
Same status code, accessible from the response object.
The JSON body in getApiResponse().getContent() typically contains a structured error from Mercado Pago. Parse it with your preferred JSON library to extract the message, error, and cause fields:
import com.mercadopago.exceptions.MPApiException;import com.fasterxml.jackson.databind.JsonNode;import com.fasterxml.jackson.databind.ObjectMapper;try { Payment payment = client.create(createRequest);} catch (MPApiException e) { int statusCode = e.getStatusCode(); String body = e.getApiResponse().getContent(); ObjectMapper mapper = new ObjectMapper(); JsonNode json = mapper.readTree(body); System.err.println("Status: " + statusCode); System.err.println("Error: " + json.path("error").asText()); System.err.println("Message: " + json.path("message").asText()); // Detailed causes, when present if (json.has("cause")) { for (JsonNode cause : json.get("cause")) { System.err.println(" Cause code: " + cause.path("code").asText()); System.err.println(" Cause desc: " + cause.path("description").asText()); } }}
The request body failed validation. Inspect the cause array in the response body for field-level error codes and descriptions. Typical causes: missing required fields, invalid data types, amounts below the minimum.
if (e.getStatusCode() == 400) { // Parse e.getApiResponse().getContent() for validation details}
401 — Unauthorized
The access token is missing, expired, or does not have the required scopes. Refresh or re-check your token.
if (e.getStatusCode() == 401) { // Re-authenticate or check MercadoPagoConfig.setAccessToken(...)}
404 — Not Found
The resource (payment, preference, device, payment intent) does not exist or does not belong to the authenticated account.
if (e.getStatusCode() == 404) { // The requested resource does not exist}
409 — Conflict
A conflicting state prevents the operation — for example, attempting to cancel a payment intent that has already been processed.
if (e.getStatusCode() == 409) { // Resolve the conflict before retrying}
422 — Unprocessable Entity
The request is syntactically valid but semantically incorrect for the current state of the resource. Check the cause array for business-rule violations.
429 — Too Many Requests
Your integration has exceeded the API rate limit. Back off and retry after a delay. Check the Retry-After header when present.
if (e.getStatusCode() == 429) { // Exponential back-off before retrying Thread.sleep(2000);}
500 — Internal Server Error
An unexpected error occurred on Mercado Pago’s side. These are usually transient — retry with exponential back-off. If the problem persists, contact Mercado Pago support and include the request ID from the response headers.
POST requests to the Mercado Pago API support idempotency: submitting the same request twice with the same x-idempotency-key returns the result of the first call rather than creating a duplicate resource. The SDK auto-generates a UUID for every POST request, but you can supply your own key via MPRequestOptions when you want deterministic deduplication (e.g., after a timeout retry):
import com.mercadopago.core.MPRequestOptions;import java.util.Map;import java.util.UUID;String idempotencyKey = UUID.randomUUID().toString(); // or derive from your order IDMPRequestOptions options = MPRequestOptions.builder() .customHeaders(Map.of("x-idempotency-key", idempotencyKey)) .build();try { Payment payment = client.create(createRequest, options);} catch (MPApiException e) { if (e.getStatusCode() >= 500 || e.getStatusCode() == 429) { // Safe to retry with the same idempotencyKey Payment payment = client.create(createRequest, options); }}
Idempotency keys are scoped to your access token and the specific endpoint. Reusing the same key across different endpoints or different request bodies has no deduplication effect.
For transient failures (network errors, 5xx responses, 429 rate limits), implement an HTTP-level retry handler using Apache HttpClient’s HttpRequestRetryHandler and register it globally via MercadoPagoConfig:
import com.mercadopago.MercadoPagoConfig;import org.apache.http.client.HttpRequestRetryHandler;import org.apache.http.protocol.HttpContext;import java.io.IOException;HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() { private static final int MAX_RETRIES = 3; @Override public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount > MAX_RETRIES) { return false; // exhausted retries } // Retry on connection resets and socket timeouts if (exception instanceof org.apache.http.conn.ConnectTimeoutException) { return true; } if (exception instanceof java.net.SocketTimeoutException) { return true; } if (exception instanceof org.apache.http.NoHttpResponseException) { return true; } return false; }};MercadoPagoConfig.setRetryHandler(retryHandler);
The HttpRequestRetryHandler operates at the Apache HttpClient transport layer and is invoked only for IOExceptions (network-level failures). API-level errors (MPApiException) — including 429 and 5xx — are not retried by this handler automatically. Implement application-level retry logic for those cases, as shown in the idempotency section above.
MPSearchRequest.getParameters() merges limit, offset, and any custom filters into a single query-parameter map, with explicit filter values taking precedence over the dedicated limit/offset fields if they overlap.
This exception extends MPException but is not related to API communication. It is thrown exclusively by WebhookSignatureValidator.validate(...) when an incoming webhook notification fails HMAC signature verification. It is never thrown during normal PointClient, PaymentClient, or other SDK client calls.