So, the “IsValid” will be checking to see if the object reference is valid. This means it’s checking to make sure that the value is not null, and that it is not marked for cleanup. This doesn’t care about whether casting is valid or not.
Your casting problem is different. When you’re casting one object to another, you’re pretty much telling the computer, “Hey, I know you think this object is a generic object of type X, but I know better than you and I’m telling you to interpret it as an object of type Y because that’s what it really is.”
You run into problems when the object you’re casting actually isn’t of type Y. Your blackboard key value is a generic object, so IF that object is anything other than AIController1 or something in that inheritance chain, you’re going to get a casting failure. I recommend using the “GetClass” node and comparing it against the AIController1 class, and if they aren’t the same, you should output an error message to the output log with the GetClass value.
When it comes to casting, it helps to think of this in terms of memory blocks. You can only cast an object downwards in the object inheritance hierarchy. So, the hierarchy chain for your AIController looks like this:
UObject → AActor → AController → AIController → AIController1
So, if you have a generic UObject and you cast it to AIController1, what’s happening on the backend is that the compiler is saying, “Hey, you see this object and the block of memory it occupies on the heap? I know you only know how the variables for the UObject are typed, but you can type the rest of the memory based off of the signature of the AIController1 class. So… like at offset X+50, the next 4 bytes would be an integer, etc.” You get into serious trouble though, when you’re wrong. If X+50 wasn’t an integer, it would be interpreted as an integer anyways and treated as an integer. In C++, this is one way you can shoot yourself in the foot if you really, really don’t know what you’re doing (Note: sometimes you can actually intend to cast something to something it’s not). A lot of compilers, API’s and engines will now do type checking to help avoid casting mistakes. Once you get your object casted to another object, the data in memory at various addresses will be interpreted as according to the class signature you casted to, and you can access the class specific variables. The casting failure is a safety measure to prevent you from accessing sections of memory if the class doesn’t match the class signature you’re casting to, because you might end up doing “really bad things”, such as redirecting a pointer address when you think you’re changing health values.
Anyways, long story short: Check your assigned behavior tree key values to be 1000% sure that you’re actually sending a value which can be casted to AIController1. If you send something like “self”, which is a character or pawn, that will break the inheritance chain and you’ll get a casting fail, and that’s easy to accidentally overlook…