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

Normalized color channel value must be between 0 to 1

Error message

Normalized color channel value must be between 0 to 1

What it means

IntegerColorChannel::fromNormalized() only accepts a float between 0 and 1 inclusive, because a normalized value is a fraction of the channel's full range, not the channel value itself (src/Colors/IntegerColorChannel.php:26-35). This method is the base for all integer channels (RGB red/green/blue 0-255, CMYK 0-100, HSV hue 0-360 / saturation / value 0-100, HSL), so passing anything outside [0, 1.0] throws InvalidArgumentException.

Source

Thrown at src/Colors/IntegerColorChannel.php:29

    /**
     * @throws InvalidArgumentException
     */
    final public function __construct(int $value)
    {
        $this->value = (int) $this->validValueOrFail($value);
    }

    /**
     * {@inheritdoc}
     *
     * @see ColorChannelInterface::fromNormalized()
     *
     * @throws InvalidArgumentException
     */
    public static function fromNormalized(float $normalized): self
    {
        if ($normalized < 0 || $normalized > 1) {
            throw new InvalidArgumentException(
                'Normalized color channel value must be between 0 to 1',
            );
        }

        return new static(intval(round($normalized * static::max())));
    }

    /**
     * {@inheritdoc}
     *
     * @see ColorChannelInterface::value()
     */
    public function value(): int
    {
        return (int) $this->value;
    }
}

View on GitHub (pinned to 5598b9e397)

Solutions

  1. Divide by the channel maximum (e.g. 128 / 255) or use channel->normalized() to produce the fraction
  2. Clamp before calling: max(0.0, min(1.0, $value))
  3. Construct the channel with its real value instead: new Red(128), which validates against 0-255
  4. When building whole colors from normalized arrays, prefer Colorspace::colorFromNormalized() so alpha defaults are handled

Example fix

// before
$channel = Rgb\Channels\Red::fromNormalized(128); // throws: must be between 0 to 1

// after
$channel = Rgb\Channels\Red::fromNormalized(128 / 255);
// or with the raw integer value:
$channel = new Rgb\Channels\Red(128);
Defensive patterns

Strategy: validation

Validate before calling

function clamp01(float $v): float { return max(0.0, min(1.0, $v)); }

$channel = Rgb\Channels\Red::fromNormalized(clamp01($pixel / 255));

Type guard

function isNormalizedValue(mixed $value): bool
{
    return is_float($value) && $value >= 0.0 && $value <= 1.0;
}

Prevention

When it happens

Trigger: Calling Red::fromNormalized(128) instead of Red::fromNormalized(128 / 255), Hsv\Channels\Saturation::fromNormalized(50) instead of 0.5, or passing a negative float; also hit indirectly when a colorspace's colorFromNormalized() receives out-of-range normalized values.

Common situations: Treating 'normalized' as a percentage (0-100) or as the raw channel value; computing ratios that can go slightly negative or above 1 due to float arithmetic or user math without clamping.

Related errors


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