juspay/hyperswitch · error
Invalid color value
Error message
Invalid color value
What it means
Thrown by toRgbArray() in the vendored invert-color code inside the payment-link page. It fires when the colour argument is falsy (null, undefined, empty string, 0) before the hex parsing in hexToRgbArray() is even attempted. In this page invert() is called with paymentDetails.theme (line 330) and paymentDetails.payment_button_colour || primaryColor (line 364-365), so a missing/empty theme field is the direct cause.
Source
Thrown at crates/router/src/core/payment_link/payment_link_initiate/payment_link.js:127
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++) {
x = c[i] / 255;
a[i] = x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
}
function invertToBW(color, bw, asArr) {
var DEFAULT_BW = {
black: "#090302",
white: "#FFFFFC",
threshold: Math.sqrt(1.05 * 0.05) - 0.05,
};View on GitHub (pinned to 9b8b89dc37)
Solutions
- Default the theme before use: var primaryColor = paymentDetails.theme || '#1a2b3c';
- Ensure the payment link create/initiate API always returns a non-empty theme for the page
- If configuring branding, set an explicit valid hex theme on the business/merchant profile used by the link
Example fix
// before
function initializeEventListeners(paymentDetails) {
var primaryColor = paymentDetails.theme;
var contrastBWColor = invert(primaryColor, true);
// after
function initializeEventListeners(paymentDetails) {
var primaryColor = paymentDetails.theme || '#1a2b3c';
var contrastBWColor = invert(primaryColor, true); Defensive patterns
Strategy: type-guard
Validate before calling
// Before calling invert()/adjustLightness()
const primaryColor = paymentDetails.theme;
if (!primaryColor) {
primaryColor = '#1a2b3c'; // branded default
} Type guard
/** @param {unknown} c @returns {c is string} */
function isUsableColor(c) {
return typeof c === 'string' && c.length > 0;
} Try / catch
try {
contrastBWColor = invert(primaryColor, true);
} catch (e) {
if (e.message === 'Invalid color value') {
contrastBWColor = '#ffffff';
} else {
throw e;
}
} Prevention
- Always default branding fields before rendering: theme || '#1a2b3c'
- Make the payment link API return a non-empty theme rather than relying on the client to cope
- Distinguish this falsy-input error from the format error (Invalid HEX color) when debugging
When it happens
Trigger: initializeEventListeners(paymentDetails) runs with paymentDetails.theme undefined or '' — e.g. a payment link created without any branding/theme, or a payment_link_details response where the theme field is absent or null.
Common situations: Merchants that never configured a theme (relying on a default the JS forgot to apply); partial API responses after a schema change renamed theme to something else; test fixtures for payment link creation omitting the branding object.
Related errors
AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16).
Data as JSON: /api/errors/678e04f73f9f7fce.
Report an issue: GitHub.