Intervention/image · error · Intervention\Image\Exceptions\ColorException

Failed to import color {color_class} to {colorspace_class}

Error message

Failed to import color {color_class} to {colorspace_class}

What it means

Converting OKLAB to OKLCH computes chroma as c = sqrt(a^2 + b^2) and hue via atan2, then constructs an OklchColor (src/Colors/Oklch/Colorspace.php:100-117). The Chroma channel is capped at 0.4, but two valid OKLAB axes of up to 0.4 each yield c up to ~0.566, so corner values overflow the chroma range and the wrapped construction throws ColorException. This is the one 'Failed to import' path that genuinely fires with valid input.

Source

Thrown at src/Colors/Oklch/Colorspace.php:112

    /**
     * Import given OKLAB color OKLCH colorspace.
     *
     * @throws ColorException
     */
    private function importOklabColor(OklabColor $color): OklchColor
    {
        $a = $color->a()->value();
        $b = $color->b()->value();

        $c = sqrt($a * $a + $b * $b);
        $h = rad2deg(atan2($b, $a));
        $h = $h < 0 ? $h + 360 : $h;

        try {
            return new Color($color->lightness()->value(), $c, $h, $color->alpha()->normalized());
        } catch (InvalidArgumentException $e) {
            throw new ColorException(
                'Failed to import color ' . $color::class . ' to ' . $this::class,
                previous: $e,
            );
        }
    }

    /**
     * Import given RGB color to OKLCH color space.
     *
     * @throws ColorException
     */
    private function importRgbColor(RgbColor $color): OklchColor
    {
        try {
            $color = $color->toColorspace(Oklab::class);
        } catch (InvalidArgumentException $e) {
            throw new ColorException(
                'Failed to import color ' . $color::class . ' to ' . $this::class,

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Pre-check the chroma before converting: sqrt(a*a + b*b) must be <= 0.4
  2. Clamp or scale the a/b axes down before conversion to bring chroma within range
  3. Catch ColorException and treat the color as out of gamut (keep it in OKLAB or clamp to max chroma)
  4. If the source lightness/alpha are corrupt, rebuild the color via Oklab\Color::create() first

Example fix

// before
$oklch = new Oklab\Color(0.5, 0.4, 0.4)->toColorspace(Oklch\Colorspace::class); // c=0.566 > 0.4 -> ColorException

// after
$scale = 0.4 / sqrt(0.4**2 + 0.4**2);
$oklab = new Oklab\Color(0.5, 0.4 * $scale, 0.4 * $scale); // chroma now exactly 0.4
$oklch = $oklab->toColorspace(Oklch\Colorspace::class);
Defensive patterns

Strategy: validation

Validate before calling

// OKLAB -> OKLCH only stays in range when the derived chroma fits
$a = $oklab->a()->value();
$b = $oklab->b()->value();
$chroma = sqrt($a * $a + $b * $b);
if ($chroma > 0.4) {
    $scale = 0.4 / $chroma;
    $oklab = Oklab\Color::create($oklab->lightness()->value(), $a * $scale, $b * $scale, $oklab->alpha()->normalized());
}
$oklch = $oklab->toColorspace(Oklch\Colorspace::class);

Type guard

function isOklabWithinOklchChroma(OklabColor $color): bool
{
    $a = $color->a()->value();
    $b = $color->b()->value();
    return sqrt($a * $a + $b * $b) <= 0.4;
}

Try / catch

try {
    $oklch = $oklab->toColorspace(Oklch\Colorspace::class);
} catch (ColorException $e) {
    // out-of-gamut corner: clamp a/b so chroma <= 0.4 and retry
}

Prevention

When it happens

Trigger: $oklab->toColorspace(Oklch\Colorspace::class) where a and b are both large, e.g. new Oklab\Color(0.5, 0.4, 0.4) gives chroma 0.5657 > 0.4. Also fires when the source lightness/alpha channels are corrupt (out of their own bounds).

Common situations: Converting saturated out-of-sRGB-gamut OKLAB colors (typical when generating wide-gamut palettes or interpolating in OKLab) to OKLCH for display; palette->toColorspace() over mixed colors hitting an extreme corner.

Related errors


AI-assisted analysis of Intervention/image@5598b9e397 (2026-08-23). Data as JSON: /api/errors/126410f81d09dc1a. Report an issue: GitHub.