{"record":{"id":"64a7644289acbabe","repo":"juspay/hyperswitch","slug":"invalid-color-value-64a764","errorCode":null,"errorMessage":"Invalid color value","messagePattern":"Invalid color value","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/router/src/core/payment_link/payment_link_status/status.js","lineNumber":40,"sourceCode":"    len = 2;\n  }\n  return (new Array(len).join(\"0\") + str).slice(-len);\n}\nfunction hexToRgbArray(hex) {\n  if (hex.slice(0, 1) === \"#\") hex = hex.slice(1);\n  var RE_HEX = /^(?:[0-9a-f]{3}){1,2}$/i;\n  if (!RE_HEX.test(hex)) throw new Error('Invalid HEX color: \"' + hex + '\"');\n  if (hex.length === 3) {\n    hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];\n  }\n  return [\n    parseInt(hex.slice(0, 2), 16),\n    parseInt(hex.slice(2, 4), 16),\n    parseInt(hex.slice(4, 6), 16),\n  ];\n}\nfunction toRgbArray(c) {\n  if (!c) throw new Error(\"Invalid color value\");\n  if (Array.isArray(c)) return c;\n  return typeof c === \"string\" ? hexToRgbArray(c) : [c.r, c.g, c.b];\n}\nfunction getLuminance(c) {\n  var i, x;\n  var a = [];\n  for (i = 0; i < c.length; i++) {\n    x = c[i] / 255;\n    a[i] = x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);\n  }\n  return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];\n}\nfunction invertToBW(color, bw, asArr) {\n  var DEFAULT_BW = {\n    black: \"#090302\",\n    white: \"#FFFFFC\",\n    threshold: Math.sqrt(1.05 * 0.05) - 0.05,\n  };","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/juspay/hyperswitch/blob/9b8b89dc378b62c9a6feda647bad4719d2de7699/crates/router/src/core/payment_link/payment_link_status/status.js#L22-L58","documentation":"Thrown by toRgbArray() in the vendored invert-color code inside the payment link status page. It triggers when the colour passed to invert() is falsy (null, undefined, empty string), before hex parsing happens. On this page the colour comes from the status payload's theme / payment_button_colour fields used for re-rendering branded UI.","triggerScenarios":"Status page render where the branding colour fields are missing, null, or '' in the payment link status response — for example a link created with no theme configured at all.","commonSituations":"Links created before branding fields existed (legacy rows with NULL theme); status payloads assembled by a different code path that omits branding; a default theme applied on the initiate page but forgotten on the status page.","solutions":["Default the colour before calling invert(): var primaryColor = theme || '#1a2b3c';","Make the status API always include a non-empty theme (server-side default)","Backfill or correct payment link rows whose theme is NULL/empty"],"exampleFix":"// before\nvar contrastBWColor = invert(primaryColor, true);\n\n// after\nvar primaryColor = paymentDetails.theme || '#1a2b3c';\nvar contrastBWColor = invert(primaryColor, true);","handlingStrategy":"type-guard","validationCode":"// Before status-page colour setup\nif (!paymentDetails.theme) {\n  paymentDetails.theme = '#1a2b3c';\n}","typeGuard":"/** @param {unknown} c @returns {c is string} */\nfunction isUsableColor(c) {\n  return typeof c === 'string' && c.length > 0;\n}","tryCatchPattern":"try {\n  contrastBWColor = invert(theme, true);\n} catch (e) {\n  if (e.message === 'Invalid color value') {\n    contrastBWColor = '#ffffff';\n  } else {\n    throw e;\n  }\n}","preventionTips":["Server-side: always include a non-empty theme in status responses","Backfill legacy payment link rows with NULL themes","Guard the falsy case separately from the malformed-hex case when triaging"],"tags":["payment-link","payment-status","null-check","client-side"],"backgroundTag":null,"analyzedSha":"9b8b89dc378b62c9a6feda647bad4719d2de7699","analyzedAt":"2026-08-16T09:01:53.433Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}