juspay/hyperswitch · error · Error

Payment Update Call Failed with error code "${response.body.

Error message

Payment Update Call Failed with error code "${response.body.error.code}" error message "${response.body.error.message}"

What it means

Thrown by manualPaymentStatusUpdateTest when PUT {BASEURL}/payments/{paymentId}/manual-update (admin api-key + X-Merchant-Id) responds non-200. Note the command first asserts response.status equals the fixture's expectedStatus (default 200), then only the 200 path is success — any non-200 response reaches this throw, so a fixture that expects an error status still trips it unless the status assertion itself fails first.

Source

Thrown at cypress-tests/cypress/support/commands.js:8110

        if (responseData.body && responseData.body.attempt_status) {
          expect(response.body.attempt_status).to.equal(
            responseData.body.attempt_status
          );
        }

        if (responseData.body && responseData.body.error_code) {
          expect(response.body.error_code).to.equal(
            responseData.body.error_code
          );
        }

        if (responseData.body && responseData.body.error_message) {
          expect(response.body.error_message).to.equal(
            responseData.body.error_message
          );
        }
      } else {
        throw new Error(
          `Payment Update Call Failed with error code "${response.body.error.code}" error message "${response.body.error.message}"`
        );
      }
    });
  });
});

Cypress.Commands.add(
  "manualPaymentUpdateNegativeTest",
  (globalState, invalidAttemptId) => {
    const merchantId = globalState.get("merchantId");
    const paymentId = globalState.get("paymentID");
    const completeUrl = `${Cypress.env("BASEURL")}/payments/${paymentId}/manual-update`;
    const adminApiKey = globalState.get("adminApiKey");

    const manualUpdateBody = {
      merchant_id: merchantId,
      attempt_id: invalidAttemptId,

View on GitHub (pinned to 9b8b89dc37)

Solutions

  1. Verify globalState.get('adminApiKey') is set and valid for the environment
  2. Check the payment's actual attempt count and use the correct attempt_id (`${paymentId}_1` assumes exactly one attempt)
  3. Ensure the payment is in a state that accepts manual update (not already terminal)
  4. If a negative status is expected, compare expectedStatus before throwing so expected non-200s do not error

Example fix

// before (commands.js)
if (response.status === 200) { ... } else {
  throw new Error(`Payment Update Call Failed ...`);
}
// after
if (response.status === 200) { ... } else if (expectedStatus !== response.status) {
  throw new Error(`Payment Update Call Failed ...`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preconditions before the manual update
expect(globalState.get('adminApiKey'), 'adminApiKey').to.not.be.empty;
expect(globalState.get('paymentID'), 'paymentID').to.not.be.empty;
// verify the attempt id actually exists before updating
cy.retrievePaymentCallTest({ globalState }).then(() => {
  /* confirm attempt count before assuming `${paymentId}_1` */
});

Type guard

const isManualUpdateRejection = (status) =>
  [400, 401, 403, 404].includes(status);

Try / catch

cy.manualPaymentStatusUpdateTest(globalState, data).catch?.((e) => {});
// or around the request in a wrapper:
cy.wrap(null)
  .then(() => cy.manualPaymentStatusUpdateTest(globalState, data))
  .catch((e) => {
    const code = e.message.match(/error code "([^"]+)"/)?.[1];
    if (code === 'IM_1' /* invalid attempt */) {
      throw new Error('attempt_id does not match the payment — inspect attempts');
    }
    throw e;
  });

Prevention

When it happens

Trigger: attempt_id `${paymentId}_1` does not match the payment's real attempt (e.g. second attempt is _2); adminApiKey invalid (401); merchant_id / X-Merchant-Id mismatch (403); payment already in a terminal state so manual update is rejected (400).

Common situations: Retries created multiple attempts so the hardcoded '_1' suffix is wrong; admin key not present in globalState for this environment; running the manual update twice; fixture declaring a non-200 expectedStatus that the else branch cannot represent.

Related errors


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