GetComponentInParent returns null even though there is a component on the parent object

Hello,
before I submit a bug report I wanted to verify if I’m not making a mistake here.

I have a prefab (it’s not instantiated, just a reference to the file) and I run the following lines on a script that’s attached somewhere down in the hierarchy of the prefab:

        Debug.Log(transform.parent.parent.GetComponent<BuildObjectConfig>()); // is not NULL
        Debug.Log(transform.parent.GetComponentInParent<BuildObjectConfig>()); // is NULL

I don’t understand why I can get the component directly from its transform but not via GetComponentFromParent. Does this have anything to do with running the script on a prefab or is it a bug/misunderstanding ?

(Unity Version 2022.3.5f1

Is the hierarchy inactive? GetComponentInParent as its docs state has a single argument stating if you want to include inactive GameObjects which defaults to false.

Nope, it’s active. (I think otherwise the normal GetComponent would also not work? Not sure about this though)

This is the object in the hierarchy. The code is run in the CoursePiece class.


This is the expected BuildObjectConfig in the grandparent.

GetComponent works fine on inactivate objects. When you say this is on a prefab, you mean it’s on an instance in the scene of course; a prefab is never active. I just tried this on 2022.3.5f1 and it works as expected so no idea.

Try printing out some more information, most likely one of the game objects in the parent chain is actually inactive.

You can add this extension method to the project to help with debugging:

public static class TransformExtensions
{
    public static string GetHierarchyInfo([NotNull]this Transform transform)
    {
        var sb = new System.Text.StringBuilder();
      
        sb.Append(transform.name);
        if(!transform.gameObject.activeInHierarchy)
        {
            sb.Append("(inactive)");
        }

        while((transform = transform.parent) != null)
        {
            sb.Insert(0, '/');
            if(!transform.gameObject.activeInHierarchy)
            {
                sb.Insert(0, "(inactive)");
            }

            sb.Insert(0, transform.name);
        }
      
#if UNITY_EDITOR
        string sceneOrAssetPath = UnityEditor.AssetDatabase.GetAssetOrScenePath(transform.gameObject);
        if(!string.IsNullOrEmpty(sceneOrAssetPath))
        {
            sb.Insert(0, '/');
            if(transform.gameObject.scene.IsValid() && !transform.gameObject.scene.isLoaded)
            {
                sb.Insert(0, "(unloaded)");
            }
          
            sb.Insert(0, sceneOrAssetPath);
        }
#endif
      
        return sb.ToString();
    }
}

And then use it like this:

Debug.Log(transform.GetHierarchyInfo());

Ah ok, no it’s not on an instantiated prefab but on the asset itself. Didn’t know that meant that the hierarchy was inactive.
Ok, so I either have to temporarily instantiate the object or add a fixed reference I guess.

Thanks

How is it even running then? When are you calling it?

Either way, just pass true for that argument would’ve been a fast fix check for you.

Keep in mind this is absolutely insane MADNESS:

I would NEVER allow this kind of code by any of my team. It’s completely and totally unsupportable and insane. There are SO many better ways to do this.

Keep in mind that using GetComponent() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.

This sort of coding is to be avoided at all costs unless you know exactly what you are doing.

If you run into an issue with any of these calls, start with the documentation to understand why.

There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.

In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.

It is ALWAYS better to go The Unity Way™ and make dedicated public fields and drag in the references you want.

Remember the first rule of GameObject.Find():

Do not use GameObject.Find();

More information: https://starmanta.gitbooks.io/unitytipsredux/content/first-question.html

More information: https://discussions.unity.com/t/899843/12

In general, DO NOT use Find-like or GetComponent/AddComponent-like methods unless there truly is no other way, eg, dynamic runtime discovery of arbitrary objects. These mechanisms are for extremely-advanced use ONLY.
If something is built into your scene or prefab, make a script and drag the reference(s) in. That will let you experience the highest rate of The Unity Way™ success of accessing things in your game.

I’m experiencing the same issue.

GetComponentInParent<>() inside of an OnValidate() call of a prefab (in project folder, not in scene) fails every time, despite the parent having the component and is active.

You haven’t really read through the thread, did you? Prefabs are not active in the hierarchy as they are not part of the hierarchy. So passing true to GetComponentInParent should work even on a prefab.

I did read it. It is strange behaviour since it is behaving differently from other getcomponent calls, which work fine in prefabs without the true added

It’s an implementation quirk that according to a post from a few years back would require significant alterations to the behavior of the engine and a complete rework of prefabs.

https://discussions.unity.com/t/767213/5

Hmmm strange quirk. Thanks for the context!