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

  1. Log the x-request-id header and full response.body to identify error.code, then look it up in the Hyperswitch error-code reference.
  2. Verify globalState paymentID and clientSecret were set by the preceding create/confirm step (stale state is the most common cause of 404/401 here).
  3. 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.
  4. 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

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


AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16). Data as JSON: /api/errors/877099c193e77498. Report an issue: GitHub.