dotnet/maui · error · ArgumentException
finishAt must be greater than beginAt
Error message
finishAt must be greater than beginAt
What it means
Thrown by Animation.Add after it has validated that beginAt and finishAt are each within [0,1]: the method additionally requires finishAt to be strictly greater than beginAt, because the child animation's duration is computed as finishAt - beginAt and a non-positive duration is meaningless.
Source
Thrown at src/Controls/src/Core/Animation.cs:54
Func<double, double> transform = AnimationExtensions.Interpolate(start, end);
Step = f => callback(transform(f));
}
/// <summary>
/// Adds an <see cref="Animation"/> object to this <see cref="Animation"/> that begins at <paramref name="beginAt"/> and finishes at <paramref name="finishAt"/>.
/// </summary>
/// <param name="beginAt">The fraction into this animation at which the added child animation will begin animating.</param>
/// <param name="finishAt">The fraction into this animation at which the added child animation will stop animating.</param>
/// <param name="animation">The animation to add.</param>
public void Add(double beginAt, double finishAt, Animation animation)
{
if (beginAt < 0 || beginAt > 1)
throw new ArgumentOutOfRangeException(nameof(beginAt));
if (finishAt < 0 || finishAt > 1)
throw new ArgumentOutOfRangeException(nameof(finishAt));
if (finishAt <= beginAt)
throw new ArgumentException("finishAt must be greater than beginAt");
animation.StartDelay = beginAt;
animation.Duration = finishAt - beginAt;
childrenAnimations.Add(animation);
}
/// <summary>
/// Runs the <paramref name="owner" /> animation with the supplied parameters.
/// </summary>
/// <param name="owner">The owning animation that will be animated.</param>
/// <param name="name">The name, or handle, that is used to access and track the animation and its state.</param>
/// <param name="rate">The time, in milliseconds, between frames.</param>
/// <param name="length">The number of milliseconds over which to interpolate the animation.</param>
/// <param name="easing">The easing function to use to transition in, out, or in and out of the animation.</param>
/// <param name="finished">An action to call when the animation is finished.</param>
/// <param name="repeat">A function that should return true if the animation should continue.</param>
public void Commit(IAnimatable owner, string name, uint rate = 16, uint length = 250, Easing easing = null, Action<double, bool> finished = null, Func<bool> repeat = null)
{View on GitHub (pinned to f377ff1c5e)
Solutions
- Ensure the arguments satisfy beginAt < finishAt (strictly), e.g. Add(0.2, 0.5, child).
- If the bounds come from variables, sort/validate them before calling Add: if (a >= b) (a, b) = (b, a).
- Skip the Add call entirely when finishAt <= beginAt if a zero-or-negative segment is legitimately unwanted.
Example fix
// before parent.Add(0.5, 0.2, child); // after parent.Add(0.2, 0.5, child);
Defensive patterns
Strategy: validation
Validate before calling
static void AddSegment(Animation parent, double beginAt, double finishAt, Animation child)
{
if (beginAt < 0 || beginAt > 1 || finishAt < 0 || finishAt > 1)
throw new ArgumentOutOfRangeException();
if (finishAt <= beginAt) (beginAt, finishAt) = (Math.Min(beginAt, finishAt), Math.Max(beginAt, finishAt));
if (finishAt <= beginAt) return; // nothing to animate
parent.Add(beginAt, finishAt, child);
} Prevention
- Always pass beginAt < finishAt in [0,1] when composing child animations.
- When bounds come from variables, sort them before calling Add.
- Add a unit test that calls Add with equal and reversed bounds to catch regressions.
When it happens
Trigger: Calling animation.Add(beginAt, finishAt, child) where finishAt <= beginAt (including the equal case), after both values already passed the [0,1] range checks.
Common situations: Composing a staggered/sequential animation and swapping the two fractions; passing finishAt = beginAt expecting a zero-length segment; computing the bounds from variables whose order flipped at runtime.
Related errors
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/016ca3fc0148b5b1.
Report an issue: GitHub.