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

  1. Clamp: Math.max(0, frameIndex) before calling
  2. Wrap-around for previous-frame: (currentFrame - 1 + numberOfFrames) % numberOfFrames
  3. 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

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


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>&lt;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&lt;0
	 */
	public Bitmap seekToFrameAndGet(@IntRange(from = 0, to = Integer.MAX_VALUE) final int frameIndex) {

View on GitHub (pinned to 26ff795f78)