OpenRA/OpenRA · error · YamlException

WithAimAnimation needs exactly one sprite body with matching

Error message

WithAimAnimation needs exactly one sprite body with matching name.

What it means

Thrown in WithAimAnimationInfo.RulesetLoaded when SingleOrDefault finds zero WithSpriteBodyInfo traits with a Name matching the Body field. WithAimAnimation switches a sprite body to an aiming sequence when the actor is targeting, so it needs exactly one WithSpriteBody to control. Note: SingleOrDefault throws InvalidOperationException if there are multiple matches, but this YamlException is thrown only for the zero-match case.

Source

Thrown at OpenRA.Mods.Common/Traits/Render/WithAimAnimation.cs:36

	{
		[Desc("Armament name")]
		public readonly string Armament = "primary";

		[SequenceReference]
		[FieldLoader.Require]
		[Desc("Displayed while targeting.")]
		public readonly string Sequence = null;

		[Desc("Which sprite body to modify.")]
		public readonly string Body = "body";

		public override object Create(ActorInitializer init) { return new WithAimAnimation(init, this); }

		public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
		{
			var match = ai.TraitInfos<WithSpriteBodyInfo>().SingleOrDefault(w => w.Name == Body);
			if (match == null)
				throw new YamlException("WithAimAnimation needs exactly one sprite body with matching name.");

			base.RulesetLoaded(rules, ai);
		}
	}

	public class WithAimAnimation : ConditionalTrait<WithAimAnimationInfo>, INotifyAiming
	{
		readonly AttackBase[] attackBases;
		readonly WithSpriteBody wsb;

		public WithAimAnimation(ActorInitializer init, WithAimAnimationInfo info)
			: base(info)
		{
			attackBases = init.Self.TraitsImplementing<AttackBase>().ToArray();
			wsb = init.Self.TraitsImplementing<WithSpriteBody>().First(w => w.Info.Name == Info.Body);
		}

		void UpdateSequence(bool isAiming)

View on GitHub (pinned to a520984d91)

Solutions

  1. Ensure the actor has exactly one WithSpriteBody trait whose Name matches the Body field on WithAimAnimation (default 'body' for both).
  2. If the Body field is customized, verify the matching WithSpriteBody Name is spelled identically.
  3. If the actor has no sprite body, remove the WithAimAnimation trait.

Example fix

// before (no matching WithSpriteBody)
WithAimAnimation:
  Body: torso
WithSpriteBody:
  Name: body

// after (names match)
WithAimAnimation:
  Body: body
WithSpriteBody:
  Name: body
Defensive patterns

Strategy: validation

Validate before calling

// Verify exactly one WithSpriteBody matches the Body field
var spriteBodies = actorInfo.TraitInfos<WithSpriteBodyInfo>();
foreach (var waa in actorInfo.TraitInfos<WithAimAnimationInfo>())
{
    var match = spriteBodies.SingleOrDefault(w => w.Name == waa.Body);
    if (match == null)
        Log.Error($"WithAimAnimation on {actorName}: no WithSpriteBody with Name '{waa.Body}'.");
}

Prevention

When it happens

Trigger: An actor has a WithAimAnimation trait with Body set to a name (default 'body'), but no WithSpriteBody trait exists on the actor with that name. This can happen if WithSpriteBody was removed or renamed, or the Body field references a non-existent body.

Common situations: Renaming a WithSpriteBody's Name without updating WithAimAnimation.Body; removing WithSpriteBody while leaving WithAimAnimation; adding WithAimAnimation to an actor that uses a different body trait (e.g. WithEmbeddedBodyPalette but no sprite body); typo in the Body field.

Related errors


AI-assisted analysis of OpenRA/OpenRA@a520984d91 (2026-08-13). Data as JSON: /api/errors/b98ff72b157390e7. Report an issue: GitHub.