Another, "Setting the parent of a transform which resides in a prefab" problem.

I have a gameObject which holds two scripts, HackManager and TextBehavior.

I use the TextBehavior class on many objects as it is my tool to display text in a multitude of situations. I just attach TextBehavior to different gameObjects and then use its methods.

HackManager generates a list of objects that are hacking targets the passes that to the TextBehavior class for processing and display.

private void DisplayScanResults (List<HackingTarget> targets) {
		textBehavior = (TextBehavior) GetComponent<TextBehavior> ();
		textBehavior.DisplayDown (targets, TextBehavior.topLeft);
	}

The TextBehavior class/script then displays the results for me as such…

// Displays a list of HackingTargets in column starting at origin. 
	public void DisplayDown (List<HackingTarget> targets, Vector3 origin) {

		foreach (HackingTarget target in targets) {
			GameObject entry = (GameObject)Instantiate (textMesh, origin, Quaternion.identity);
			// Add the appropriate listener script.  
			entry.AddComponent<ScanClickLink> ();
			ScanClickLink clickscript = entry.GetComponent<ScanClickLink> ();
			clickscript.Target = target;
			entry.transform.parent = gameObject.transform;  // THIS IS WHERE THE ERROR OCCURS
			entry.transform.localPosition = origin;
			TextMeshPro tMesh = entry.GetComponent <TextMeshPro> ();
			tMesh.text = BuildTargetDesc (target);
			tMesh.ForceMeshUpdate ();
			float newY = tMesh.mesh.bounds.center.y + tMesh.mesh.bounds.size.y + .2f;
			Vector3 temp = new Vector3 (0, newY, 0);
			origin -= temp;
		}
	}

I attach an additional script to each textmesh which handles additional interface from user. Then parent the textMeshes to the gameObject which holds the mentioned scripts. This is where the problem crops up. The commented line throws, “Setting the parent of a transform which resides in a prefab is disabled to prevent data corruption”.

I should also add, this technique worked great for months until I migrated the game code to a new laptop. That SEEMS to be when this problem cropped up. I may be mistaken though. The error may have been introduced somewhere else.

“Setting the parent of a transform which resides in a prefab is disabled to prevent data corruption.”

I tried a few cases of this and here are the situations I found where it logs that error:

(1) Script is in an instantiated GameObject. Target child is a prefab.
(2) Script is in a prefab. Target child is instantiated.
(3) Both are prefabs.

Obviously, there’s no error when both are instantiated. It works in that case.

It may be helpful to note that at runtime, all instantiated prefabs (according to some Unity talks I watched) are supposed to have no knowledge of themselves coming from prefabs.

May we see where you are getting your List elements?

Well, as i already mentioned on that other question you most likely execute this method on a prefab. It would help to see the call stack of your error. From where and how do you call “DisplayScanResults”?

I guess that the gameobject with your “HackManager” is actually a prefab and you execute your methods on the prefab instance.

You make the textMesh instance a child of the gameobject this script is attached to. Since the textMesh clearly is an instance in the scene the only logical reason for this error is that the gameobject you want to use as parent is actually a prefab.

@tpainton and anyone else who runs into this issue

So I ran into this issue as well, here’s what i found was the culprit…

In my particular case I have a GameManager that is an instantiated singleton and in a Menu’s OnClick event I call the SwapLevel function in GameManager. After a lot of playing around, reading this and other threads like it, what I’ve found is this… because the OnClick event procs a call to GameManager.SwapLevel and not GameManager.instance.SwapLevel I had to change the code in SwapLevel to make everything in it refer to the instance, otherwise its all considered the prefab…

So the code

void SwapLevel(int level)
    {
        if (level >= LevelStuff.Length || level < 0)
            return;

        if (transform.childCount > 0)
            foreach (Transform t in transform)
                Destroy(t.gameObject);

        GameObject go = Instantiate(LevelStuff[level]) as GameObject;
        go.transform.SetParent(transform);
        curLevel = level;
    }

Became

void SwapLevel(int level)
    {
        if (level >= GameManager.instance.LevelStuff.Length || level < 0)
            return;

        if (GameManager.instance.transform.childCount > 0)
            foreach (Transform t in GameManager.instance.transform)
                Destroy(t.gameObject);

        GameObject go = Instantiate(GameManager.instance.LevelStuff[level]) as GameObject;
        go.transform.SetParent(GameManager.instance.transform);
        curLevel = level;
    }

Hope this helps!