juspay/hyperswitch · error
Invalid HEX color: "${hex}"
Error message
Invalid HEX color: "${hex}" What it means
Identical vendored invert-color code, but embedded in the payment link status page (crates/router/src/core/payment_link/payment_link_status/status.js). hexToRgbArray() throws when, after removing a leading '#', the string is not exactly 3 or 6 hex digits. This page re-renders branding colours while polling the payment status, so an invalid branding hex breaks the status view.
Source
Thrown at crates/router/src/core/payment_link/payment_link_status/status.js:29
} catch (e) {
console.error("Error decoding and parsing string URI:", e);
return uri;
}
}
/**
* Ref - https://github.com/onury/invert-color/blob/master/lib/cjs/invert.js
*/
function padz(str, len) {
if (len === void 0) {
len = 2;
}
return (new Array(len).join("0") + str).slice(-len);
}
function hexToRgbArray(hex) {
if (hex.slice(0, 1) === "#") hex = hex.slice(1);
var RE_HEX = /^(?:[0-9a-f]{3}){1,2}$/i;
if (!RE_HEX.test(hex)) throw new Error('Invalid HEX color: "' + hex + '"');
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
return [
parseInt(hex.slice(0, 2), 16),
parseInt(hex.slice(2, 4), 16),
parseInt(hex.slice(4, 6), 16),
];
}
function toRgbArray(c) {
if (!c) throw new Error("Invalid color value");
if (Array.isArray(c)) return c;
return typeof c === "string" ? hexToRgbArray(c) : [c.r, c.g, c.b];
}
function getLuminance(c) {
var i, x;
var a = [];
for (i = 0; i < c.length; i++) {View on GitHub (pinned to 9b8b89dc37)
Solutions
- Fix the stored branding value to a strict 3/6-digit hex on the business/merchant profile or the payment link
- Apply the same defensive default in status.js as in payment_link.js before calling invert()
- Add hex validation where branding is authored so both pages stop receiving bad values
- Keep the two vendored copies in sync — a fix applied to only one file leaves the other throwing
Example fix
// before (status.js)
var contrastBWColor = invert(primaryColor, true);
// after
var HEX_RE = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
var primaryColor =
typeof theme === 'string' && HEX_RE.test(theme.trim()) ? theme : '#1a2b3c';
var contrastBWColor = invert(primaryColor, true); Defensive patterns
Strategy: validation
Validate before calling
const HEX_RE = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
function normalizeHexColor(c, fallback = '#1a2b3c') {
return typeof c === 'string' && HEX_RE.test(c.trim()) ? c.trim() : fallback;
}
// use in status.js render path:
var theme = normalizeHexColor(statusPayload.theme); Type guard
/** @param {unknown} c @returns {c is string} */
function isHexColor(c) {
return typeof c === 'string' && /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(c.trim());
} Try / catch
try {
contrastBWColor = invert(theme, true);
} catch (e) {
if (/Invalid HEX color/.test(e.message)) {
contrastBWColor = '#ffffff';
} else {
throw e;
}
} Prevention
- Apply the same hex validation to the status page as to the initiate page
- Fix branding data at the source (API/DB) so neither page receives bad values
- Test the status page with the same branding edge cases as the initiate page
When it happens
Trigger: Opening the payment link status page for a link whose theme or payment_button_colour is a named colour ('blue'), an rgb()/rgba() string, 4/8-digit hex, or contains whitespace/invalid characters; invert() is invoked on those values during status-page colour setup.
Common situations: Same root cause as the initiate page: branding values persisted without hex validation; values copied from CSS or a design tool ('#1A2B3CCC' from Figma exports alpha hex); inconsistent data between the initiate and status payloads after a partial fix on only one page.
Related errors
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/2386ab73775e2534.
Report an issue: GitHub.