daimajia/AndroidViewAnimations · error · RuntimeException
Can not be less than -1, -1 is infinite loop
Error message
Can not be less than -1, -1 is infinite loop
What it means
AnimationComposer.repeat(int times) validates the loop-count argument at composition time: the minimum legal value is INFINITE (-1), which means loop forever. Any value below -1 (e.g. -2) is rejected with a RuntimeException because there is no meaningful repeat count less than infinite; 0 means play once (repeat disabled), positive values repeat that many times.
Solutions
- Clamp before calling: pass Math.max(-1, times) or map any negative to INFINITE (-1)
- If you want a single playthrough, pass 0 or omit repeat(); only -1 means infinite
- Validate the count at its source (user input/API payload) and normalize there
- If the count is untrusted, wrap the composer chain in try-catch and fall back to a sane default like repeat(1)
Example fix
// before int times = serverConfig.getRepeatCount(); // may be -3 YoYo.with(Techniques.Bounce).repeat(times).playOn(view); // after int times = serverConfig.getRepeatCount(); if (times < -1) times = -1; // INFINITE YoYo.with(Techniques.Bounce).repeat(times).playOn(view);
Defensive patterns
Strategy: validation
Validate before calling
static int safeRepeat(int times) {
final int INFINITE = -1;
if (times < INFINITE) {
throw new IllegalArgumentException("repeat must be >= -1 (INFINITE), got " + times);
}
return times;
}
// usage: YoYo.with(Techniques.Tada).repeat(safeRepeat(userCount)).playOn(view); Try / catch
try {
YoYo.with(Techniques.Bounce).repeat(times).playOn(view);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("less than -1")) {
Log.w("YoYo", "bad repeat count " + times + ", using default");
YoYo.with(Techniques.Bounce).repeat(1).playOn(view);
} else {
throw e;
}
} Prevention
- Clamp any computed or externally supplied repeat count to >= -1 before calling repeat()
- Remember the semantics: 0 = play once, -1 = infinite, positive n = repeat n times
- Unit-test composition code with edge inputs (0, -1, -2) to catch off-by-one errors early
- Centralize repeat-count parsing/normalization in one helper instead of inlining raw values
When it happens
Trigger: Calling YoYo.with(...).repeat(n) with n < -1 — typically a computed count that drifted negative (e.g. repeat(count - 2) when count <= 1), a misdecoded remote-config value, or confusing -1 semantics with other negative sentinels.
Common situations: Passing user-supplied or server-supplied repeat counts without clamping; off-by-one arithmetic on repeat counters; developers using negative values as 'disabled' flags instead of 0.
Related errors
AI-assisted analysis of daimajia/AndroidViewAnimations@6a35c466d2 (2026-09-08).
Data as JSON: /api/errors/86557f16fd5cde38.
Report an issue: GitHub.
Appendix: source
Thrown at library/src/main/java/com/daimajia/androidanimations/library/YoYo.java:156
public AnimationComposer pivot(float pivotX, float pivotY) {
this.pivotX = pivotX;
this.pivotY = pivotY;
return this;
}
public AnimationComposer pivotX(float pivotX) {
this.pivotX = pivotX;
return this;
}
public AnimationComposer pivotY(float pivotY) {
this.pivotY = pivotY;
return this;
}
public AnimationComposer repeat(int times) {
if (times < INFINITE) {
throw new RuntimeException("Can not be less than -1, -1 is infinite loop");
}
repeat = times != 0;
repeatTimes = times;
return this;
}
public AnimationComposer repeatMode(int mode) {
repeatMode = mode;
return this;
}
public AnimationComposer withListener(Animator.AnimatorListener listener) {
callbacks.add(listener);
return this;
}
public AnimationComposer onStart(final AnimatorCallback callback) {
callbacks.add(new EmptyAnimatorListener() {View on GitHub (pinned to 6a35c466d2)