Intervention/image · error · Intervention\Image\Exceptions\InvalidArgumentException
Invalid hsl() color syntax "{input}"
Error message
Invalid hsl() color syntax "{input}" What it means
The HSL string decoder accepts 'hsl(...)' or 'hsla(...)' with a numeric hue (optionally suffixed 'deg'), saturation and luminance as plain numbers or percentages, and an optional alpha ('/ 0.5', comma or space separated, in 0-1 decimal or N% form). Strings that start with 'hsl' but violate this grammar throw the 'Invalid hsl() color syntax' InvalidArgumentException. Component values are matched as non-negative decimals, so negatives or letters fail here before any range validation happens.
Source
Thrown at src/Colors/Hsl/Decoders/StringColorDecoder.php:53
return false;
}
if (!str_starts_with(strtolower($input), 'hsl')) {
return false;
}
return true;
}
/**
* Decode hsl color strings.
*
* @throws InvalidArgumentException
*/
public function decode(mixed $input): ColorInterface
{
if (preg_match(self::PATTERN, $input, $matches) !== 1) {
throw new InvalidArgumentException('Invalid hsl() color syntax "' . $input . '"');
}
$values = array_map(fn(string $value): int => match (strpos($value, '%')) {
false => intval(trim($value)),
default => intval(trim(str_replace('%', '', $value))),
}, [$matches['h'], $matches['s'], $matches['l']]);
// alpha value
if (array_key_exists('a', $matches)) {
$values[] = match (strpos($matches['a'], '%')) {
false => floatval(trim($matches['a'])),
default => floatval(trim(str_replace('%', '', $matches['a']))) / 100,
};
}
return new Color(...$values);
}
}View on GitHub (pinned to 5598b9e397)
Solutions
- Use canonical syntax: 'hsl(0, 100%, 50%)' or 'hsla(0, 100%, 50% / 0.5)'
- Validate with a regex or try/catch around parse before trusting user input
- Normalize input: trim whitespace, replace Unicode minus/quotes with ASCII equivalents
- Build programmatically when values are dynamic: Hsl\Color::create(0, 100, 50, 0.5)
Example fix
// before
$color = Hsl\Color::parse('hsla(-20, 100%, 50% / 50%)');
// after
$color = Hsl\Color::parse('hsla(340, 100%, 50% / 0.5)'); Defensive patterns
Strategy: validation
Validate before calling
if (!preg_match('/^hsla? ?\( ?[0-9.]+(deg)?(, ?| )[0-9.]+%?(, ?| )[0-9.]+%?( ?\/ ?|[, ] ?)?((0?\.[0-9]+)|1\.0|\.[0-9]+|[0-9]{1,3}%|1|0)? ?\)$/i', trim($input))) {
// reject before Hsl\Color::parse()
} Type guard
function isHslString(mixed $input): bool
{
return is_string($input)
&& str_starts_with(strtolower(trim($input)), 'hsl')
&& str_contains($input, '(')
&& str_ends_with(trim($input), ')');
} Try / catch
use Intervention\Image\Exceptions\InvalidArgumentException as ImageArg;
try {
$color = Hsl\Color::parse($input);
} catch (ImageArg $e) {
$color = Hsl\Color::create(0, 0, 0); // or re-prompt the user
} Prevention
- Validate hsl() strings at the input boundary with the same grammar
- Use canonical comma-separated syntax with % on s and l
- Express alpha as a 0-1 decimal or percent, never >1
- Prefer Hsl\Color::create() when values are programmatic
When it happens
Trigger: Hsl\Color::parse('hsl(-10, 50%, 50%)') (negative hue); 'hsl(0 100% 50' (missing ')'); 'hsl(0, 100%, 50% / 1.5)' (alpha grammar only allows 0-1 decimals or up-to-3-digit percents); 'hsl(360deg,100%,50%,)' (trailing comma); smart quotes/Unicode minus from copied text.
Common situations: Free-text color fields in CMS/forms; CSS strings pasted from design tools with alternate spacing or Unicode punctuation; dynamically assembled strings with missing delimiters.
Related errors
- Unable to parse HSL color from input "{input}"
- Invalid cmyk() color syntax "{input}"
- Unable to parse HSV color from input "{input}"
- Number of color channels must be 3 or 4 for {class}
- Normalized color value must be in range 0 to 1
AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23).
Data as JSON: /api/errors/d88aa3795e4b27ae.
Report an issue: GitHub.