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

Unable to import color {colorClass} to {class}

Error message

Unable to import color {colorClass} to {class}

What it means

When RemoveAnimationModifier's $position is a string, normalizePosition() first casts numeric strings to int, then tries the strict pattern ^[0-9]{1,3}%$ for percentages. Any other string — negative percents, 4+ digit percents, spaces, decimals, unit suffixes — throws InvalidArgumentException. The regex is deliberately tight: 1-3 digits followed immediately by '%'.

Source

Thrown at src/Colors/Cmyk/Colorspace.php:85

    /**
     * {@inheritdoc}
     *
     * @see ColorspaceInterface::importColor()
     *
     * @throws ColorException
     */
    public function importColor(ColorInterface $color): CmykColor
    {
        return match ($color::class) {
            OklchColor::class,
            OklabColor::class,
            HsvColor::class,
            NamedColor::class,
            HslColor::class => $this->importViaRgbColor($color),
            RgbColor::class => $this->importRgbColor($color),
            CmykColor::class => $color,
            default => throw new ColorException(
                'Unable to import color ' . $color::class . ' to ' . $this::class,
            ),
        };
    }

    /**
     * Import given RGB color to CMYK colorspace.
     *
     * @throws ColorException
     */
    private function importRgbColor(RgbColor $color): CmykColor
    {
        $c = (255 - $color->red()->value()) / 255.0 * 100;
        $m = (255 - $color->green()->value()) / 255.0 * 100;
        $y = (255 - $color->blue()->value()) / 255.0 * 100;
        $k = intval(round(min([$c, $m, $y])));

        $c = intval(round($c - $k));

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Normalize input before calling: strip spaces, cast integer-like values to int, format percents as 'NN%' with 1-3 digits.
  2. Validate with the same pattern: preg_match('/^[0-9]{1,3}%$/', $value) === 1 before passing a string.
  3. Pass an int when you know the frame index; strings are only needed for percentage selection.
  4. For values above 999% (nonsensical) clamp or reject outright at your input layer.

Example fix

// before
$image->removeAnimation($request->input('position')); // '50 %' throws

// after
$position = preg_replace('/\s+/', '', $request->input('position'));
if (is_numeric($position)) {
    $position = (int) $position;
}
$image->removeAnimation($position);
Defensive patterns

Strategy: validation

Validate before calling

$position = preg_replace('/\s+/', '', (string) $position);
if (is_numeric($position)) {
    $position = max(0, (int) $position);
} elseif (preg_match('/^[0-9]{1,3}%$/', $position) !== 1) {
    throw new InvalidArgumentException('Bad position: ' . $position);
}
$image->removeAnimation($position);

Type guard

function isRemovableAnimationPosition(int|string $position): bool
{
    return is_int($position)
        ? $position >= 0
        : (is_numeric($position) || preg_match('/^[0-9]{1,3}%$/', $position) === 1);
}

Try / catch

try {
    $image->removeAnimation($position);
} catch (Intervention\Image\Exceptions\InvalidArgumentException $e) {
    // fall back to frame 0
    $image->removeAnimation(0);
}

Prevention

When it happens

Trigger: ->removeAnimation('50 %') (space), ->removeAnimation('-10%'), ->removeAnimation('1000%'), ->removeAnimation('50percent'), ->removeAnimation('first').

Common situations: User input trimmed insufficiently ('50 ' or '50 %'); percentage values from spreadsheets formatted like '50.0%'; locale-specific formatting; attempts to use frame labels or relative keywords.

Related errors


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