koral--/android-gif-drawable · error · IndexOutOfBoundsException
Frame index is not positive
Error message
Frame index is not positive
What it means
seekToFrame validates the zero-based frame index is non-negative before scheduling an async seek. Because the check < 0 rejects only negatives, passing 0 is legal; a negative index throws IndexOutOfBoundsException with the message 'Frame index is not positive'.
Solutions
- Clamp: Math.max(0, frameIndex) before calling
- Wrap-around for previous-frame: (currentFrame - 1 + numberOfFrames) % numberOfFrames
- Catch IndexOutOfBoundsException and call seekToFrame(0)
Example fix
// before gifDrawable.seekToFrame(currentFrame - 1); // after gifDrawable.seekToFrame(Math.max(0, currentFrame - 1));
Defensive patterns
Strategy: validation
Validate before calling
if (frameIndex < 0) { frameIndex = 0; } Type guard
int clampFrame(int idx, int frames) { return Math.max(0, Math.min(idx, frames - 1)); } Try / catch
try { gifDrawable.seekToFrame(idx); } catch (IndexOutOfBoundsException e) { gifDrawable.seekToFrame(0); } Prevention
- Clamp frame indices to [0, getNumberOfFrames()-1]
- Implement 'previous frame' with wrap-around modulo
- Never use -1 as a frame sentinel when calling this API
When it happens
Trigger: Calling seekToFrame() with a negative frame index, e.g. currentFrame - 1 when already at frame 0, or a sentinel -1 from saved state.
Common situations: 'Previous frame' buttons decrementing past 0; loop arithmetic modulo bugs; deserializing state where -1 means 'no frame'.
Related errors
- Position is not positive
- Sample size out of range <1, 65535>
- Bitmap is recycled
- Bitmap ia too small, size must be greater than or equal to…
- Only Config.ARGB_8888 is supported. Current bitmap config
AI-assisted analysis of koral--/android-gif-drawable@26ff795f78 (2026-09-10).
Data as JSON: /api/errors/777c66e385b28b1a.
Report an issue: GitHub.
Appendix: source
Thrown at android-gif-drawable/src/main/java/pl/droidsonroids/gif/GifDrawable.java:574
throw new IllegalArgumentException("Position is not positive");
}
synchronized (mNativeInfoHandle) {
mNativeInfoHandle.seekToTime(position, mBuffer);
}
mInvalidationHandler.sendEmptyMessageAtTime(MSG_TYPE_INVALIDATION, 0);
}
/**
* Like {@link #seekTo(int)} but uses index of the frame instead of time.
* If <code>frameIndex</code> exceeds number of frames, seek stops at the end, no exception is thrown.
*
* @param frameIndex index of the frame to seek to (zero based)
* @throws IllegalArgumentException if <code>frameIndex</code><0
*/
public void seekToFrame(@IntRange(from = 0, to = Integer.MAX_VALUE) final int frameIndex) {
if (frameIndex < 0) {
throw new IndexOutOfBoundsException("Frame index is not positive");
}
mExecutor.execute(new SafeRunnable(this) {
@Override
public void doWork() {
mNativeInfoHandle.seekToFrame(frameIndex, mBuffer);
mInvalidationHandler.sendEmptyMessageAtTime(MSG_TYPE_INVALIDATION, 0);
}
});
}
/**
* Like {@link #seekToFrame(int)} but performs operation synchronously and returns that frame.
*
* @param frameIndex index of the frame to seek to (zero based)
* @return frame at desired index
* @throws IndexOutOfBoundsException if frameIndex<0
*/
public Bitmap seekToFrameAndGet(@IntRange(from = 0, to = Integer.MAX_VALUE) final int frameIndex) {View on GitHub (pinned to 26ff795f78)