unoplatform/uno · error · InvalidOperationException
Failed load the animation
Error message
Failed load the animation
What it means
A catch-all wrapper inside the OnJsonChanged callback that swallows any exception raised while loading/re-parsing the animation (including error 20) and re-throws it as a new InvalidOperationException with the original as InnerException. Note the message has a typo ('Failed load the animation'). This wraps the whole TryCreate/SetAnimation/Play block, so it also fires on failures inside SetAnimation or Play, not only parse failures.
Source
Thrown at src/AddIns/Uno.UI.Lottie/LottieVisualSource.Skottie.cs:140
this.Log().Debug($"Version: {animation.Version} Duration: {animation.Duration} Fps:{animation.Fps} InPoint: {animation.InPoint} OutPoint: {animation.OutPoint}");
}
}
else
{
throw new InvalidOperationException("Failed to load animation.");
}
SetAnimation(animation);
if (_playState != null)
{
var (fromProgress, toProgress, looped) = _playState;
Play(fromProgress, toProgress, looped);
}
}
catch (Exception ex)
{
throw new InvalidOperationException("Failed load the animation", ex);
}
}
}
else
{
throw new NotSupportedException($"Failed to load animation: {sourceUri}");
}
// Force layout to recalculate
player.InvalidateMeasure();
player.InvalidateArrange();
if (_playState != null)
{
var (fromProgress, toProgress, looped) = _playState;
Play(fromProgress, toProgress, looped);
}
else if (player.AutoPlay)View on GitHub (pinned to 0418340488)
Solutions
- Inspect ex.InnerException (and InnerException.InnerException for error 20) — the true failure is nested, not the 'Failed load the animation' message.
- Fix the underlying cause identified via InnerException (parse error, null state, etc.).
- Enable Debug logging on the LottieVisualSource to capture the Version/Duration/Fps trace that prints only on successful parse, confirming whether TryCreate ever succeeded.
- If updating this add-in source, consider preserving the original exception type instead of blanket-wrapping into InvalidOperationException.
Example fix
// before — blanket wrap hides root cause
catch (Exception ex)
{
throw new InvalidOperationException("Failed load the animation", ex);
}
// after — let parse failures surface their real type, only wrap unknowns
catch (InvalidOperationException) { throw; }
catch (Exception ex)
{
throw new InvalidOperationException("Failed load the animation", ex);
} Defensive patterns
Strategy: try-catch
Try / catch
try { player.Source = lottieSource; }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Failed load the animation"))
{
// real cause is in ex.InnerException (possibly nested)
Log.Error(ex.InnerException, "Lottie load failed");
ShowFallback();
} Prevention
- Always unwrap InnerException when catching this wrapper.
- Enable Debug logging on LottieVisualSource to capture parse traces.
- Treat this exception as a signal to investigate InnerException, not as the root cause.
When it happens
Trigger: Any exception thrown within the OnJsonChanged body: Skottie.Animation.TryCreate returning false (re-wrapped error 20), a null-reference in SetAnimation, or Play throwing because the play state is invalid. The catch wraps every statement from stream creation through Play().
Common situations: Hot-reload or cache-invalidation flow delivering a malformed updatedJson payload; calling Play before the animation finished initializing; a SkiaSharp version mismatch where Animation members behave unexpectedly. Because it re-wraps, the real root cause is in InnerException and easy to miss.
Related errors
- Failed to load animation.
- Failed to load animation: {sourceUri}
- NotImplemented_GetFormattedString
- value
- Unable to find [MapGrid] template part
AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13).
Data as JSON: /api/errors/96bba9d84a05727d.
Report an issue: GitHub.