juspay/hyperswitch · error · Error
Retrieve Payment Call Failed with error code "${response.bod
Error message
Retrieve Payment Call Failed with error code "${response.body.error.code}" error message "${response.body.error.message}" What it means
Throw in the Cypress command retrievePaymentCallTest (cypress-tests/cypress/support/commands.js:4595). The command calls GET /payments/{id}?force_sync=true&expand_attempts=true and expects 200; any non-200 status hits this throw, embedding response.body.error.code and response.body.error.message. It means the retrieve call itself failed — bad/expired credentials, unknown payment id, router 5xx, or the payment is in a state the spec did not declare via its fixture data. If the error body has no error object, the message will show 'undefined', which itself hints at an unexpected response shape.
Source
Thrown at cypress-tests/cypress/support/commands.js:4595
`${payment_id}_${attempt}` &&
response.body.status === "succeeded"
) {
expect(response.body.attempts[key].status).to.equal("charged");
} else if (
response.body.attempts[key].attempt_id ===
`${payment_id}_${attempt}` &&
response.body.status === "requires_customer_action"
) {
expect(response.body.attempts[key].status).to.equal(
"authentication_pending"
);
} else {
expect(response.body.attempts[key].status).to.equal("failure");
}
}
}
} else {
throw new Error(
`Retrieve Payment Call Failed with error code "${response.body.error.code}" error message "${response.body.error.message}"`
);
}
});
});
}
);
Cypress.Commands.add(
"retrievePaymentCallAutoRetryTest",
({ globalState, attempt = null, expectedIntentStatus }) => {
const paymentId = globalState.get("paymentID");
const baseUrl = globalState.get("baseUrl");
const apiKey = globalState.get("apiKey");
const maxRetries = globalState.get("max_auto_retries_enabled");
// Check if Step-Up retry is enabled from globalState flag
const isStepUpRetryEnabled =View on GitHub (pinned to 9b8b89dc37)
Solutions
- Log the x-request-id header and full response.body to identify error.code, then look it up in the Hyperswitch error-code reference.
- Verify globalState paymentID and clientSecret were set by the preceding create/confirm step (stale state is the most common cause of 404/401 here).
- If the payment is legitimately failed/unexpected-state, pass fixture data for that outcome or assert the error code instead of letting the command throw.
- If force_sync intermittently 5xxes, retry the retrieve once — it is a polling-style endpoint.
Example fix
// before
} else {
throw new Error(`Retrieve Payment Call Failed with error code "${response.body.error.code}" error message "${response.body.error.message}"`);
}
// after
} else {
throw new Error(`Retrieve Payment Call Failed (status=${response.status}) with error code "${response.body?.error?.code}" error message "${response.body?.error?.message}" (request_id=${response.headers["x-request-id"]}, payment_id=${paymentId})`);
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: ensure state needed for the retrieve exists before calling retrievePaymentCallTest
const paymentId = globalState.get("paymentID");
const clientSecret = globalState.get("clientSecret");
if (!paymentId) throw new Error("globalState.paymentID missing — run create/confirm before retrieve");
if (!clientSecret) throw new Error("globalState.clientSecret missing — cannot authorize retrieve"); Type guard
function isPaymentRetrieveSuccess(body) {
return body && typeof body === "object" && !body.error && typeof body.status === "string";
}
function isApiErrorBody(body) {
return body && typeof body === "object" && body.error && typeof body.error.code === "string";
} Try / catch
// treat retrieve as pollable: one bounded retry on transient 5xx, fail hard otherwise
const tryRetrieve = (n) => cy.retrievePaymentCallTest({ globalState, data }).then(() => null).catch((e) => {
if (n > 0 && /5\\d\\d/.test(e.message)) return tryRetrieve(n - 1);
throw new Error(`${e.message} (payment_id=${globalState.get("paymentID")}, request_id logged by command)`);
});
tryRetrieve(1); Prevention
- Always seed globalState (paymentID, clientSecret) in the same test before retrieving; never assume state from a previous spec.
- Pass fixture data describing the expected payment state so the command asserts instead of throwing on non-200.
- Guard the error template with optional chaining (response.body?.error?.code) so a missing error object does not yield 'undefined'.
- Log the x-request-id so the failing retrieve can be traced in server logs.
When it happens
Trigger: GET /payments/{paymentID} returns non-200: paymentID in globalState is stale/wrong (404), publishable key/admin key invalid (401), force_sync triggers a router/connector error (5xx), or the payment legitimately failed and the spec passed success data.
Common situations: Test retries where globalState was reset between the create and retrieve steps; wrong baseUrl or API keys in env config; connector declines surfacing as failed attempts during force_sync; running specs against an environment where the payment was already terminal.
Related errors
- Invalid authentication type: ${response.body.authentication_
- Invalid authentication type ${response.body.authentication_t
- Invalid capture method ${response.body.capture_method}
- Business Profile call failed ${response.body.error.message}
- Business Profile Update Failed: ${response.body.error?.messa
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/877099c193e77498.
Report an issue: GitHub.