{"record":{"id":"44221ae92b5ced7b","repo":"juspay/hyperswitch","slug":"payment-update-call-failed-with-error-code-resp","errorCode":null,"errorMessage":"Payment Update Call Failed with error code \"${response.body.error.code}\" error message \"${response.body.error.message}\"","messagePattern":"Payment Update Call Failed with error code \"(.+?)\" error message \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cypress-tests/cypress/support/commands.js","lineNumber":8110,"sourceCode":"        if (responseData.body && responseData.body.attempt_status) {\n          expect(response.body.attempt_status).to.equal(\n            responseData.body.attempt_status\n          );\n        }\n\n        if (responseData.body && responseData.body.error_code) {\n          expect(response.body.error_code).to.equal(\n            responseData.body.error_code\n          );\n        }\n\n        if (responseData.body && responseData.body.error_message) {\n          expect(response.body.error_message).to.equal(\n            responseData.body.error_message\n          );\n        }\n      } else {\n        throw new Error(\n          `Payment Update Call Failed with error code \"${response.body.error.code}\" error message \"${response.body.error.message}\"`\n        );\n      }\n    });\n  });\n});\n\nCypress.Commands.add(\n  \"manualPaymentUpdateNegativeTest\",\n  (globalState, invalidAttemptId) => {\n    const merchantId = globalState.get(\"merchantId\");\n    const paymentId = globalState.get(\"paymentID\");\n    const completeUrl = `${Cypress.env(\"BASEURL\")}/payments/${paymentId}/manual-update`;\n    const adminApiKey = globalState.get(\"adminApiKey\");\n\n    const manualUpdateBody = {\n      merchant_id: merchantId,\n      attempt_id: invalidAttemptId,","sourceCodeStart":8092,"sourceCodeEnd":8128,"githubUrl":"https://github.com/juspay/hyperswitch/blob/9b8b89dc378b62c9a6feda647bad4719d2de7699/cypress-tests/cypress/support/commands.js#L8092-L8128","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Verify globalState.get('adminApiKey') is set and valid for the environment","Check the payment's actual attempt count and use the correct attempt_id (`${paymentId}_1` assumes exactly one attempt)","Ensure the payment is in a state that accepts manual update (not already terminal)","If a negative status is expected, compare expectedStatus before throwing so expected non-200s do not error"],"exampleFix":"// before (commands.js)\nif (response.status === 200) { ... } else {\n  throw new Error(`Payment Update Call Failed ...`);\n}\n// after\nif (response.status === 200) { ... } else if (expectedStatus !== response.status) {\n  throw new Error(`Payment Update Call Failed ...`);\n}","handlingStrategy":"try-catch","validationCode":"// preconditions before the manual update\nexpect(globalState.get('adminApiKey'), 'adminApiKey').to.not.be.empty;\nexpect(globalState.get('paymentID'), 'paymentID').to.not.be.empty;\n// verify the attempt id actually exists before updating\ncy.retrievePaymentCallTest({ globalState }).then(() => {\n  /* confirm attempt count before assuming `${paymentId}_1` */\n});","typeGuard":"const isManualUpdateRejection = (status) =>\n  [400, 401, 403, 404].includes(status);","tryCatchPattern":"cy.manualPaymentStatusUpdateTest(globalState, data).catch?.((e) => {});\n// or around the request in a wrapper:\ncy.wrap(null)\n  .then(() => cy.manualPaymentStatusUpdateTest(globalState, data))\n  .catch((e) => {\n    const code = e.message.match(/error code \"([^\"]+)\"/)?.[1];\n    if (code === 'IM_1' /* invalid attempt */) {\n      throw new Error('attempt_id does not match the payment — inspect attempts');\n    }\n    throw e;\n  });","preventionTips":["Do not hardcode the '_1' attempt suffix — derive it from the payment's attempt count","Ensure adminApiKey exists in globalState before any admin endpoint call","Only run manual update on payments in non-terminal states","Fix the commands.js else-branch so expected non-200 statuses do not throw"],"tags":["cypress","manual-update","admin-api","payments","attempt-id"],"backgroundTag":null,"analyzedSha":"9b8b89dc378b62c9a6feda647bad4719d2de7699","analyzedAt":"2026-08-16T09:01:53.433Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}