{"record":{"id":"1e2b5cd27c66d24a","repo":"juspay/hyperswitch","slug":"failed-to-fetch-qr-code-image-response-statuste","errorCode":null,"errorMessage":"Failed to fetch QR code image: ${response.statusText}","messagePattern":"Failed to fetch QR code image: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cypress-tests-v2/cypress/support/redirectionHandler.js","lineNumber":413,"sourceCode":"      // No CORS workaround needed\n      cy.window().its(\"location.origin\").should(\"eq\", expected_url.origin);\n    } else {\n      // Workaround for CORS to allow cross-origin iframe\n      cy.origin(\n        expected_url.origin,\n        { args: { expected_url: expected_url.origin } },\n        ({ expected_url }) => {\n          cy.window().its(\"location.origin\").should(\"eq\", expected_url);\n        }\n      );\n    }\n  }\n}\n\nasync function fetchAndParseQRCode(url) {\n  const response = await fetch(url, { encoding: \"binary\" });\n  if (!response.ok) {\n    throw new Error(`Failed to fetch QR code image: ${response.statusText}`);\n  }\n  const blob = await response.blob();\n  const reader = new FileReader();\n  return await new Promise((resolve, reject) => {\n    reader.onload = () => {\n      const base64Image = reader.result.split(\",\")[1]; // Remove data URI prefix\n      const image = new Image();\n      image.src = base64Image;\n\n      image.onload = () => {\n        const canvas = document.createElement(\"canvas\");\n        const ctx = canvas.getContext(\"2d\");\n        canvas.width = image.width;\n        canvas.height = image.height;\n        ctx.drawImage(image, 0, 0);\n\n        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n        const qrCodeData = jsQR(","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/juspay/hyperswitch/blob/9b8b89dc378b62c9a6feda647bad4719d2de7699/cypress-tests-v2/cypress/support/redirectionHandler.js#L395-L431","documentation":"Thrown by fetchAndParseQRCode in cypress-tests-v2 redirection support. It fetches the QR image URL (from a UPI intent response's qrInfoData.qrLink/qr field) with the browser fetch API and throws when response.ok is false, embedding response.statusText. This is a test-side network assertion, not app code.","triggerScenarios":"cy flows that parse a UPI intent QR: the fetch of the QR image URL returns 404 (session/link expired), 401/403 (signed URL or auth issue), or 5xx from the QR service — response.ok is false and the error carries the status text.","commonSituations":"The QR link is short-lived and the test reached it after expiry (slow CI, retries, cy.wait delays); the environment's QR host is unreachable from the CI runner (DNS/proxy/firewall); baseUrl routing differences between sandbox and integ so the QR URL points at the wrong host.","solutions":["Fetch the QR immediately after receiving the payment response, before any cy.wait, so the signed link has not expired","Manually curl/GET the failing URL from the same CI environment to see the real status code and body","Re-run the payment initiation to obtain a fresh QR link before parsing","Verify the URL used comes from response.body.qrInfoData.qrLink (or qr) exactly, with no truncation or encoding issues"],"exampleFix":"// before\nconst response = await fetch(url, { encoding: 'binary' });\nif (!response.ok) {\n  throw new Error(`Failed to fetch QR code image: ${response.statusText}`);\n}\n\n// after (retry once with a fresh short-lived link in mind)\nasync function fetchQr(url, attempts = 2) {\n  for (let i = 0; i < attempts; i++) {\n    const response = await fetch(url, { encoding: 'binary' });\n    if (response.ok) return response;\n    if (i === attempts - 1) {\n      throw new Error(`Failed to fetch QR code image: ${response.status} ${response.statusText}`);\n    }\n    await new Promise((r) => setTimeout(r, 2000));\n  }\n}","handlingStrategy":"retry","validationCode":"// Before parsing, confirm the QR link exists and looks fetchable\nconst qrLink = response.body.qrInfoData?.qrLink || response.body.qrInfoData?.qr;\nif (!qrLink || !/^https?:\\/\\//.test(qrLink)) {\n  throw new Error(`No QR link to parse (qrInfoData: ${JSON.stringify(response.body.qrInfoData)})`);\n}","typeGuard":null,"tryCatchPattern":"// Short-lived signed QR links: retry briefly, then fail with the status\nasync function fetchQrWithRetry(url, attempts = 3) {\n  let lastErr;\n  for (let i = 0; i < attempts; i++) {\n    const response = await fetch(url, { encoding: 'binary' });\n    if (response.ok) return response;\n    lastErr = new Error(`Failed to fetch QR code image: ${response.status} ${response.statusText}`);\n    await new Promise((r) => setTimeout(r, 2000));\n  }\n  throw lastErr;\n}","preventionTips":["Fetch the QR immediately after receiving the payment response, before any cy.wait","Initiate a fresh payment (new QR link) rather than retrying an old URL after long waits","Verify CI can reach the QR host (DNS/proxy) — 404 here usually means expiry, 5xx usually means reachability"],"tags":["cypress","qr-code","upi","network","test-infrastructure"],"backgroundTag":null,"analyzedSha":"9b8b89dc378b62c9a6feda647bad4719d2de7699","analyzedAt":"2026-08-16T09:01:53.433Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}