{"record":{"id":"b64aafe0e4d519d3","repo":"Intervention/image","slug":"failed-to-invert-color","errorCode":null,"errorMessage":"Failed to invert color","messagePattern":"Failed to invert color","errorType":"exception","errorClass":"Intervention\\Image\\Exceptions\\ColorException","httpStatus":null,"severity":"error","filePath":"src/Colors/AbstractColor.php","lineNumber":167,"sourceCode":"        $hsl = clone $this->toColorspace(HslColorspace::class);\n        $hsl->channel(Saturation::class)->scale($level);\n\n        return $hsl->toColorspace($this->colorspace());\n    }\n\n    /**\n     * {@inheritdoc}\n     *\n     * @see ColorInterface::withInversion()\n     *\n     * @throws ColorException\n     */\n    public function withInversion(): ColorInterface\n    {\n        try {\n            $rgb = $this->toColorspace(RgbColorspace::class);\n        } catch (InvalidArgumentException) {\n            throw new ColorException('Failed to invert color');\n        }\n\n        try {\n            $inverted = new \\Intervention\\Image\\Colors\\Rgb\\Color(\n                255 - $rgb->channel(Red::class)->value(),\n                255 - $rgb->channel(Green::class)->value(),\n                255 - $rgb->channel(Blue::class)->value(),\n                $rgb->alpha()->normalized(),\n            );\n            return $inverted->toColorspace($this->colorspace());\n        } catch (InvalidArgumentException) {\n            throw new ColorException('Failed to invert color');\n        }\n    }\n\n    public function jsonSerialize(): mixed\n    {\n        return $this->toString();","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/Intervention/image/blob/5598b9e39751c34afc5cdee84abef77f92c26f68/src/Colors/AbstractColor.php#L149-L185","documentation":"Final ColorizeModifier range check: blue must be an int in -100..100. Reaching it means red and green are already valid and only blue is out of range. All three guards exist so the exception names the exact offending argument.","triggerScenarios":"$image->colorize(0, 0, -101); only the blue channel coming from a different, unvalidated source (e.g. a preset file).","commonSituations":"Preset/recipe files (JSON/YAML) with historical values outside the range after a version tightened validation; copy-pasted snippets with extreme blue shifts like -150 for 'sepia-like' effects.","solutions":["Clamp blue (and ideally all channels) with max(-100, min(100, $b)).","Validate preset files on load against a -100..100 schema instead of trusting stored numbers.","Audit all call sites once: the same clamp must cover red and green too."],"exampleFix":"// before\n$image->colorize(0, 0, $preset['blue']); // -101 throws\n\n// after\n$clamp = fn (int $v): int => max(-100, min(100, $v));\n$image->colorize($clamp(0), $clamp(0), $clamp($preset['blue']));","handlingStrategy":"validation","validationCode":"$clamp = fn (int $v): int => max(-100, min(100, $v));\n$image->colorize($clamp($r), $clamp($g), $clamp($b));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate stored presets/recipes against a -100..100 schema on load.","Apply the same clamp to values read from config files.","Cover all three channels in tests at the boundaries (-100, 0, 100)."],"tags":["colorize","color","argument-validation","modifier","php"],"backgroundTag":"argument-out-of-range","analyzedSha":"5598b9e39751c34afc5cdee84abef77f92c26f68","analyzedAt":"2026-08-23T02:17:31.068Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}