Yalantis/uCrop · error · IllegalArgumentException

Animation duration cannot be negative value.

Error message

Animation duration cannot be negative value.

What it means

CropImageView.setImageToWrapCropBoundsAnimDuration only accepts durations > 0; passing 0 or a negative value throws this IllegalArgumentException despite the message only mentioning negative values (the annotation also demands a minimum of 100 ms). It controls the animation that snaps the image to wrap the crop bounds after gestures.

Source

Thrown at ucrop/src/main/java/com/yalantis/ucrop/view/CropImageView.java:187

    /**
     * This method sets maximum width for resulting cropped image
     *
     * @param maxResultImageSizeY - size in pixels
     */
    public void setMaxResultImageSizeY(@IntRange(from = 10) int maxResultImageSizeY) {
        mMaxResultImageSizeY = maxResultImageSizeY;
    }

    /**
     * This method sets animation duration for image to wrap the crop bounds
     *
     * @param imageToWrapCropBoundsAnimDuration - duration in milliseconds
     */
    public void setImageToWrapCropBoundsAnimDuration(@IntRange(from = 100) long imageToWrapCropBoundsAnimDuration) {
        if (imageToWrapCropBoundsAnimDuration > 0) {
            mImageToWrapCropBoundsAnimDuration = imageToWrapCropBoundsAnimDuration;
        } else {
            throw new IllegalArgumentException("Animation duration cannot be negative value.");
        }
    }

    /**
     * This method sets multiplier that is used to calculate max image scale from min image scale.
     *
     * @param maxScaleMultiplier - (minScale * maxScaleMultiplier) = maxScale
     */
    public void setMaxScaleMultiplier(float maxScaleMultiplier) {
        mMaxScaleMultiplier = maxScaleMultiplier;
    }

    /**
     * This method scales image down for given value related to image center.
     */
    public void zoomOutImage(float deltaScale) {
        zoomOutImage(deltaScale, mCropRect.centerX(), mCropRect.centerY());
    }

View on GitHub (pinned to f788b534b4)

Solutions

  1. Pass a positive value; use the default if you don't need customization.
  2. Clamp the incoming duration: Math.max(100, configuredDuration).
  3. If your source value may be 0/unset, guard it and only call the setter when > 0.
  4. Follow the @IntRange(from = 100) contract: prefer durations of at least 100 ms so the animation is visible.

Example fix

// before
cropImageView.setImageToWrapCropBoundsAnimDuration(prefs.getInt("anim_duration", 0));
// after
long duration = Math.max(100, prefs.getInt("anim_duration", 300));
cropImageView.setImageToWrapCropBoundsAnimDuration(duration);
Defensive patterns

Strategy: validation

Validate before calling

long safeDuration = configuredDurationMs > 0 ? Math.max(100, configuredDurationMs) : 300;
cropImageView.setImageToWrapCropBoundsAnimDuration(safeDuration);

Type guard

boolean isValidAnimDuration(long durationMs) { return durationMs >= 100; }

Try / catch

try {
    cropImageView.setImageToWrapCropBoundsAnimDuration(duration);
} catch (IllegalArgumentException e) {
    cropImageView.setImageToWrapCropBoundsAnimDuration(300); // default
}

Prevention

When it happens

Trigger: Calling setImageToWrapCropBoundsAnimDuration(0) or with any negative long; passing an uninitialized/unparsed duration variable that defaulted to 0.

Common situations: Reading a duration from config/preferences where the key is missing (parsed as 0); passing a constant meant for another API where 0 means 'no animation'; copy-pasting a duration in the wrong unit and truncating to 0.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/f17960e6d8e6cf91. Report an issue: GitHub.