How does Lyra avoid "Accessed None" errors with its thread-safe GetMainAnimBP Property Access?

Hello,

I’m building an animation system using the Lyra architecture (a base ABP with logic, and a ABPLayerBase to hold the layers, linked via an interface).

I’ve replicated the GetMainAnimBPThreadSafe pattern in my animation layer. It’s a pure, thread-safe function that calls GetOwningComponent.GetAnimInstance and casts to my base ABP.

I am calling this function from my AnimGraph (in state transitions, etc.) using Property Access nodes.

The Problem: My system works, but my log is spammed with Accessed None trying to read property CallFunc_GetABPBase_Threadsafe_ReturnValue errors.

I’m 99% sure this is a startup race condition where the Property Access node is called on Frame 1 before the AnimInstance is fully initialized, so my “getter” function correctly returns None.

My Question: When I look through the Lyra project, I see many Property Access nodes in the AnimGraph that don’t seem to be protected by an IsValid? check or a Select node with a fallback.

How does Lyra’s implementation of this pattern robustly handle this startup race condition and avoid logging these “Accessed None” errors? Am I missing a key “Fast Path” caching step, or is there another mechanism that guarantees the reference is valid?

Thank you!

Hi, any linked graphs should be initialized as part of initializing animation on the owning skeletal mesh component. It’s during that call that we also create the main anim instance (in USkeletalMeshComponent::InitializeAnimScriptInstance), so both the owning component and the main anim instance should be valid by the point that the property access calls are during or prior to the graph update.

It’d be useful to get some more information on your setup:

  • Can you share a log with the warnings/errors in it?
  • I assume you only see the spam in the log on the first frame and not subsequently?
  • Are you able to check the type being returned from GetOwningComponent.GetAnimInstance to double-check that it isn’t the cast that’s failing?
  • Can you track down whether each call to GetABPBase_Threadsafe causes the error, or are there specific places that you’re using that function within the graph that are causing the issue?

Thanks

Just thinking about this a bit more - how are you linking the sub-graphs/layers that have the failing property access, are you using LinkAnimClassLayers?

Hi Euan,

My error is: Warning: Accessed None trying to read property CallFunc_GetABPBase_TS_ReturnValue

I am getting cast failed, at the start, and often after playing montages, but not always.

I am setting the LinkAnimClassLayers on begin play in my Char BP. I also set it when switching weapons.

Is there any rules on data manipulation or specific data types that should not be done in the layered abp via property access?

Hi, could you share the log from when the error occurs, rather than just the specific message? It’d be useful to see the log to check whether there’s any other useful information in there.

> I am getting cast failed, at the start, and often after playing montages, but not always.

Do you know if the cast is failing because the owning anim instance type is different, or is it because GetOwningComponent.GetAnimInstance is returning null?

> I am setting the LinkAnimClassLayers on begin play in my Char BP. I also set it when switching weapons.

I spent a bit of time trying to replicate the issue with this setup but I didn’t have any luck setting the layers on BeginPlay in Lyra rather than the default functionality of when the weapons are equipped. One thing you could try is setting the anim blueprint that you want to use as the default layer directly on the linked layered nodes. I don’t think that would change the behaviour but it might be worth checking. It’s this property if you want to try:

[Image Removed]> Is there any rules on data manipulation or specific data types that should not be done in the layered abp via property access?

Nothing apart from the obvious ones that you already mentioned, like making sure that any operation is thread-safe if you’re running the property access during the graph update. And it does make sense in general to check that objects are valid before operating on them. But in this case the owning anim instance should always be valid, which is why we don’t have a check.

I’m not sure how feasible this would be, but if you were able to put together a cut down version of the project that repros the issue and send it over, I could debug it directly to see what’s going on.

Thanks for the info. When I’m getting the “Accessed None trying to read property CallFunc_GetABPBase” the cast seems to be returning none, but at other times it’s also returning itself ( the layerBase_abp ) I noticed in Lyra there is a second cast to it’s own abp if the initial cast fails, but it doesn’t seem to return anything beyond error info so didn’t think I needed that. I have already set the default layer in the linked layer settings to the base layer and that doesn’t seem to make any difference. The data itself seems to read correctly so I’m wondering if it’s something in the way I am setting the linked layers?

I can’t send over the full project, but I do have a test project I can send over using the same setup. I made it match the basics of what I’m doing and it does have a few return none errors, so if you could look over that one that would be great. If you can see what’s wrong with it I could apply that to my main more complex project. If that works for you, how do I send it?

I didn’t notice until now as I had the getABP not marked as threadsafe. With it set this way everything worked, I guess the game thread knows to wait, but it results in a lot of calls to that function.

Would there be a better alternative method for passing the base abp? I could add it as an input on all the layers.

Ok yeah, that makes more sense as to why you were seeing a different behaviour. Whether the function is marked as thread safe or not affects the point at which it’s called in the frame, so if it’s marked as non-threadsafe it’ll run earlier in the frame than a threadsafe function which will run in-place during the anim graph update. Having said that, I’m still a bit surprised that the reference wasn’t valid when it was called as a non-threadsafe function since the mesh and the anim instance should still have existed at that point.

Something else I also realized is that since Lyra was implemented, we’ve added a native function that you can call rather than having to implement GetOwningComponent.GetAnimInstance in blueprint. It’s called Blueprint_GetMainAnimInstance, so you can just call that directly via property access. It’ll be slightly more performant than a blueprint-implemented function.

> Would there be a better alternative method for passing the base abp? I could add it as an input on all the layers.

Is there concern here about performance? Using a variable and passing it via a pin into the layers is a valid way to get data to where you need it. You could use the property access node to get the owning anim instance at the start of BlueprintThreadSafeUpdateAnimation, then just cache it as a variable and pass that around.

Thanks.

Performance wise, I switched to this method for better performance so hopefully I can keep using it. My comment was to say is there a better way in that a way that is more stable not more performant.

Regarding my previous post, sorry if it was confusing. I meant when I had this getMainABP function running as not threadsafe, I did not have any not valid errors it ran fine. I realized I was not using the setup correctly and taking advantage of thread safe performance so switched it to threadsafe based on the lyra example, and that’s when I introduced the return none log spam. ( Although the system did work data wise ).

hmm switching to use GetMainAnimInstance seems like it might have solved my issue, I will test more and come back. How does it work differently?

And incase it’s not fixed/ so I can try and understand the issue here is one of my issues here in more details:

Error message:

Blueprint Runtime Error: “Accessed None trying to read property CallFunc_GetABPBase_ReturnValue_28”. Node: AimOffset Player ‘(None)’ Graph: AimOffsetLayer Function: Execute Ubergraph ABP Layers Base Blueprint: ABP_LayersBase

Layer that the error message happens on:

[Image Removed]

How I’m getting the base abp

[Image Removed]

And here is how I am getting the the data fed into that layer. This function is called on the blueprintThreadsafeUpdateAnimation graph

[Image Removed]

Let me know if you want to see the project and how to send it to you if so.

Also I did play with getting the anim instance ans chaching on blueprint init of the layered abp but that didn’t provide me with the updating data. I didn’t try doing it on update every frame, that sounds like it could work but following thr Lyra setup I assumed this way was more performant.

Hi,

> Regarding my previous post, sorry if it was confusing. I meant when I had this getMainABP function running as not threadsafe, I did not have any not valid errors it ran fine. I realized I was not using the setup correctly and taking advantage of thread safe performance so switched it to threadsafe based on the lyra example, and that’s when I introduced the return none log spam. ( Although the system did work data wise ).

Ok yeah, that makes sense. The function anim bp function (in your case GetABPBase) should be marked as thread safe. The call to GetOwningComponent.GetAnimInstance isn’t thread safe so when it’s included in a threadsafe function like GetABPBase it runs up front before the update and we cache the value for wherever it’s referenced within the graph.

> hmm switching to use GetMainAnimInstance seems like it might have solved my issue, I will test more and come back. How does it work differently?

Looking at the implementation of Blueprint_GetMainAnimInstance, it’s actually marked as thread safe as well, which I’m assuming is why the issue goes away when you use it. However, all it’s doing is wrapping the call to GetOwningComponent.GetAnimInstance. So it shouldn’t really be marked as thread safe because technically it’s not. The chances of it ever causing a problem are low, but in theory you could access some data via GetMainAnimInstance that’s being written to on another thread. We do similar things to this quite often in our projects, so this is an ok solution if it works for you.

> Blueprint Runtime Error: “Accessed None trying to read property CallFunc_GetABPBase_ReturnValue_28”. Node: AimOffset Player ‘(None)’ Graph: AimOffsetLayer Function: Execute Ubergraph ABP Layers Base Blueprint: ABP_LayersBase

I have managed to get a repro where the cast will fail on the first frame. But I only hit it once, I didn’t get any spam. It may just be an issue with your setup being slightly different and that exposes an issue in Lyra. If you happen to be calling the function more on the first frame than in Lyra, you would see more errors.

> Let me know if you want to see the project and how to send it to you if so.

Yeah, I think we’re at a point where it’d be useful to get a proper repro. It would have to be a cut down version of the project that I could run on my end without any dependencies, or a project you recreate that repros the issue. I’ve shared a link to a Box folder with you that you can upload the project to. You should have received a separate email with the details.

> Also I did play with getting the anim instance ans chaching on blueprint init of the layered abp but that didn’t provide me with the updating data. I didn’t try doing it on update every frame, that sounds like it could work but following thr Lyra setup I assumed this way was more performant.

That’s also slightly odd. We store by reference in blueprint, so if you get the anim instance and store it, then use that reference to access variables on the anim instance in subsequent frames, those values should be the same as the updated values as you see in the main anim instance.

Thanks Euan, I have places the cut down test project in box. Let me know if you find anything.

Using BlueprintThreadSafeUpdateAnimation to cast an instance does seem to work, I thought you meant BlueprintThreadSafeInitilizeAnimation in the layer base sorry. But Blueprint_GetMainAnimInstance does seem to work better.

Forgot to mention, the easiest way to see the error come up is by equipping/switching weapons using the number keys. Thanks for your help, I’m curious to why certain data works and others not.

Just a quick update on this. I’ve been able to track down the problem with your repro. It turns out that it’s an order of execution issue. It’s not that the property access is failing, it’s that it hasn’t actually run by the point we’re trying to access the data from within the anim graph. When you link in the sub-graphs, we call Initialize_AnyThread on all of the anim nodes to initialize them. Certain anim nodes (like the BlendSpacePlayer) call GetEvaluateGraphExposedInputs as part of that. GetEvaluateGraphExposedInputs is intended to retrieve the property values used by the node. But, at this point in the update, the sub-graph has just been linked, so we haven’t called Update on it yet. That means the property access system hasn’t run yet (the pre-update calls at least) to fix up the property references, so the value is invalid, and you get the error on the first frame. I think that we don’t see this so much in Lyra because it’s specific to a few nodes like the BlendSpacePlayer, and we generally don’t make the call to get the owning anim instance as often in the initial state of the sub-graph.

I’m going to talk to the dev team about this one to see what they want to do. I’ll follow up once I have more info.

Thanks for the update, interesting.. Let me know if you hear anything back. In the meantime I tried casting to local versions of the variables feeding the blendspacePlayer and that seemed to help. eg. [Image Removed]

I’ve had a few conversations with the dev team about this, and we’ve decided on a workaround/solution. If you’re able to make code changes, I’m going to make the following change to UAnimInstance::InitializeAnimation which should also be fine for you to integrate locally:

	// before initialize, need to recalculate required bone list
	RecalcRequiredBones();
 
	GetProxyOnGameThread<FAnimInstanceProxy>().Initialize(this);
 
        // fix start
	if (AnimBlueprintClass)
	{
		AnimBlueprintClass->ForEachSubsystem(this, [this](const FAnimSubsystemInstanceContext& InContext)
		{
			if (InContext.SubsystemStruct == FAnimSubsystem_PropertyAccess::StaticStruct())
			{
				FAnimSubsystemUpdateContext UpdateContext(InContext, this, 0.f);
				InContext.Subsystem.OnPreUpdate_GameThread(UpdateContext);
 
                                return EAnimSubsystemEnumeration::Stop;
			}
 
			return EAnimSubsystemEnumeration::Continue;
		});
	}
        // fix end
 
	{
#if DO_CHECK
		// Allow us to validate callbacks within user c

That runs the property access system for properties bound to the pre-event graph callsite on the game thread will have been updated before Initialize_AnyThread is called on any of the animation nodes. The problem still remains with pre-event graph calls on a worker thread (which I’m going to look at a similar fix elsewhere for) and the post-event graph calls (which we aren’t going to change so those will always generate errors).

I also got advice from the dev team that chaining property access calls in the way that is shown in Lyra at the moment goes against best practice. There’s no guaranteed ordering of those calls, so they may get called out of order which could give unexpected results. So the advice is only to ever have one level of property access call (ie. from the input to the blendspace, etc, in your setup).

To fixup Lyra to follow this, I’m going to make a change to the GetMainAnimBPThreadSafe bp function so that it calls the native method directly rather than using property access. So the function will look like this in future:

[Image Removed]Similar to what we’d discussed previously, if you were to make that change to call Blueprint_GetMainAnimInstance then the issue should also be resolved, in which case you don’t need the code change I included above.

Thanks. I will test this out and let you know if I have any more issues. :folded_hands:

Sounds good. I’ll leave this thread open for now, it’ll auto close in a couple of weeks if you don’t run into any other problems. I’ve committed the change I mentioned so that Lyra now uses Blueprint_GetMainAnimInstance, you’ll see that in the 5.8 release.

Great thanks for all your help. Yeah I think we can close this now as it seems stable. :slight_smile: