{"record":{"id":"a19367832bf6ff00","repo":"Intervention/image","slug":"offset-is-not-in-the-range-of-frames","errorCode":null,"errorMessage":"Offset is not in the range of frames","messagePattern":"Offset is not in the range of frames","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Drivers/Gd/Modifiers/SliceAnimationModifier.php","lineNumber":24,"sourceCode":"\nuse Intervention\\Image\\Exceptions\\InvalidArgumentException;\nuse Intervention\\Image\\Interfaces\\ImageInterface;\nuse Intervention\\Image\\Interfaces\\SpecializedInterface;\nuse Intervention\\Image\\Modifiers\\SliceAnimationModifier as GenericSliceAnimationModifier;\n\nclass SliceAnimationModifier extends GenericSliceAnimationModifier implements SpecializedInterface\n{\n    /**\n     * {@inheritdoc}\n     *\n     * @see ModifierInterface::apply()\n     *\n     * @throws InvalidArgumentException\n     */\n    public function apply(ImageInterface $image): ImageInterface\n    {\n        if ($this->offset >= $image->count()) {\n            throw new InvalidArgumentException('Offset is not in the range of frames');\n        }\n\n        $image->core()->slice($this->offset, $this->length);\n\n        return $image;\n    }\n}\n","sourceCodeStart":6,"sourceCodeEnd":32,"githubUrl":"https://github.com/Intervention/image/blob/5598b9e39751c34afc5cdee84abef77f92c26f68/src/Drivers/Gd/Modifiers/SliceAnimationModifier.php#L6-L32","documentation":"sliceAnimation($offset, $length) keeps only the frames starting at the 0-based offset. The GD implementation first checks that the offset is smaller than the number of frames in the core and throws InvalidArgumentException otherwise. A decoded still image counts as one frame, so only offset 0 is valid there; a five-frame GIF accepts offsets 0 through 4.","triggerScenarios":"$image->sliceAnimation(5) on a 5-frame GIF (valid maximum is 4); sliceAnimation(1) or higher on a non-animated single-frame image; an offset computed as count($frames) to grab the last frame (off-by-one); applying the call to images that may or may not be animated.","commonSituations":"Frame selectors driven by user input; 1-based indexing assumptions; 'take the last frame' logic; batch jobs processing mixed still/animated content.","solutions":["Use a 0-based offset strictly smaller than $image->count()","For the last frame: $image->sliceAnimation($image->count() - 1, 1)","Clamp dynamic offsets: $offset = min($offset, $image->count() - 1)","Guard stills with $image->isAnimated() before slicing"],"exampleFix":"// before: off-by-one on a 5-frame gif\n$image->sliceAnimation(5);\n\n// after: keep only the last frame\n$image->sliceAnimation($image->count() - 1, 1);","handlingStrategy":"validation","validationCode":"$offset = 5;\n\nif ($offset >= $image->count()) {\n    throw new InvalidArgumentException(sprintf(\n        'Offset %d out of range for %d frames',\n        $offset,\n        $image->count()\n    ));\n}\n\n$image->sliceAnimation($offset, $length);","typeGuard":"function isValidSliceOffset(int $offset, ImageInterface $image): bool\n{\n    return $offset >= 0 && $offset < $image->count();\n}","tryCatchPattern":"use Intervention\\Image\\Exceptions\\InvalidArgumentException;\n\ntry {\n    $image->sliceAnimation($offset, $length);\n} catch (InvalidArgumentException $e) {\n    // clamp to the last valid frame and retry\n    $image->sliceAnimation($image->count() - 1, $length);\n}","preventionTips":["Remember offsets are 0-based; the last frame is count() - 1.","Clamp dynamic offsets with min($offset, $image->count() - 1).","Branch on $image->isAnimated() before frame-slicing still images.","Validate frame selectors from user input against $image->count()."],"tags":["gd","animation","frames","slice","offset","validation"],"backgroundTag":"index-out-of-range","analyzedSha":"5598b9e39751c34afc5cdee84abef77f92c26f68","analyzedAt":"2026-08-23T02:17:31.068Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}