PrefabUtility.SaveAsPefabAsset() crashes unity and results in a "broken" prefab

I have made a script that takes a prefab, adds several components and then instantiate the new prefab in a scene in which runs in the editor. That script works as intended and the gameObject is instantiated as intended. Now I want to be able to instantiate more copies of the gameObject during runtime but cannot do it because it is not in the resources folder. For this reason (and some other) I want to, in addition to instantiating the gameObject, create a prefab in the resources folder.

To create the prefab I use the PrefabUtility.SaveAsPrefabAsset(InstantiatedObject, Path), but when I run it Unity just spins and I cannot do anything other than force quit the application. The method did create a prefab at the given path, but when trying to open it an error is thrown:

Opening Prefab Mode failed: The Prefab at 'Assets/LanguageVR/Resources/InteractableObjects/Et eple.prefab' is broken.
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

When I reopen Unity I am greeted with

A default asset was created for 'Assets/LanguageVR/Resources/InteractableObjects/Et eple.prefab' because the asset importer crashed on it last time.
You can select the asset and use the 'Assets -> Reimport' menu command to try importing it again, or you can replace the asset and it will auto import again.

My code is here:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;
using Valve.VR.InteractionSystem;
using Photon.Pun;
using UnityEditor;

//[ExecuteInEditMode]
public class InteractableObject : MonoBehaviour
{
    [Tooltip("Click to instantiate the prefab in scene. Sometimes the old is not removed, manually delete it then")]
    [SerializeField] private bool instantiatePrefab = false;

    [Tooltip("The word to appear over the object")]
    [SerializeField] private new string name;

    // Changing font not working (out of the box)
    //[Tooltip ("Font of name displayed in scene")]
    //[SerializeField] private Font font;

    [Tooltip("The GameObject to be instantiated in the scene")]
    [SerializeField] private GameObject physicalObject;

    [Tooltip("The audioclip associated with this object")]
    [SerializeField] private AudioClip audioClip;

    private GameObject instantiatedObject;
    private GameObject instantiatedTextObject;
    private TextMesh textMesh;

    private AudioSource audioSource;

    void Awake()
    {
        instantiatedObject = transform.Find(physicalObject.name + "(Clone)").gameObject;
        instantiatedTextObject = instantiatedObject.transform.Find("Text").gameObject;

        audioSource = GetComponent<AudioSource>();
        textMesh = GetComponentInChildren<TextMesh>();
    }

    void Update()
    {
        Throwable throwable = instantiatedObject.GetComponent<Throwable>();
        if (throwable.IsAttached() && !instantiatedTextObject.activeSelf && throwable.IsMine())
        {
            instantiatedTextObject.SetActive(true);
        }
        else if (!throwable.IsAttached() && instantiatedTextObject.activeSelf)
        {
            instantiatedTextObject.SetActive(false);
        }

        if (instantiatedTextObject.activeSelf)
        {
            Transform headTransform = ViveManager.Instance.head.transform;
            instantiatedTextObject.transform.rotation = Quaternion.LookRotation(instantiatedTextObject.transform.position - headTransform.position);
        }
    }

    private void OnValidate()
    {
        if (instantiatePrefab)
        {
            InstantiatePhysicalObject();
            InstantiateText();
            SaveToResources();
            instantiatePrefab = false;
        }
    }

    // Instansiates the given gameobject
    private void InstantiatePhysicalObject()
    {
        // Destroy previous object if a new one is selected
        if (instantiatedObject != null)
        {
            StartCoroutine(Destroy(instantiatedObject));
        }

        instantiatedObject = Instantiate(physicalObject);
        instantiatedObject.transform.parent = this.transform;
        instantiatedObject.transform.localPosition = Vector3.zero;
        instantiatedObject.AddComponent<Rigidbody>();

        int numberOfChildren = instantiatedObject.transform.childCount;
        if (numberOfChildren == 0)
        {
            if (!instantiatedObject.GetComponent<MeshCollider>())
            {
                instantiatedObject.AddComponent<MeshCollider>();
            }
            instantiatedObject.GetComponent<MeshCollider>().convex = true;
        }
        else
        {
            for (int i = 0; i < numberOfChildren; i++)
            {
                GameObject child = instantiatedObject.transform.GetChild(i).gameObject;
                if (!child.GetComponent<MeshCollider>())
                {
                    child.AddComponent<MeshCollider>();
                }
                child.GetComponent<MeshCollider>().convex = true;
            }
        }

        AudioSource instantiatedAudioSource = instantiatedObject.AddComponent<AudioSource>();
        instantiatedAudioSource.clip = audioClip;
        instantiatedAudioSource.playOnAwake = false;


        Throwable throwable = instantiatedObject.AddComponent<Throwable>();
        instantiatedObject.AddComponent<Interactable>();
        instantiatedObject.AddComponent<VelocityEstimator>();
        PhotonView photonView = instantiatedObject.AddComponent<PhotonView>();

        photonView.ObservedComponents = new List<Component>();
        photonView.ObservedComponents.Add(throwable);
        photonView.OwnershipTransfer = OwnershipOption.Takeover;
        photonView.Synchronization = ViewSynchronization.UnreliableOnChange;
    }

    private void InstantiateText()
    {
        instantiatedTextObject = new GameObject("Text");
        instantiatedTextObject.transform.parent = instantiatedObject.transform;
        instantiatedObject.transform.localPosition = Vector3.zero;

        textMesh = instantiatedTextObject.AddComponent<TextMesh>();

        textMesh.text = name;
        textMesh.transform.localPosition = Vector3.zero;
        textMesh.transform.localScale = Vector3.one * 0.01f;
        textMesh.fontSize = 100;
        textMesh.anchor = TextAnchor.MiddleCenter;
        //textMesh.font = font;
    }

    private void SaveToResources()
    {
        PrefabUtility.SaveAsPrefabAsset(instantiatedObject, "Assets/LanguageVR/Resources/InteractableObjects/" + textMesh.text + ".prefab");
    }

    // Can only destroy gameobjects in OnValidate using a coroutine
    IEnumerator Destroy(GameObject go)
    {
        yield return new WaitForEndOfFrame();
        DestroyImmediate(go);
    }
}

The instantiation happens when a checkbox is ticked in the editor, which first instantiates the gameObject and adds several components, then instantiates a textMesh adding it to the newly instantiated gameObject, before finally saving it to resources in SaveToResources().

Am I using PrefabUtility.SaveAsPrefabAsset() wrong, or is this a bug?
I am using 2018.3.3f1, but am updating to 3.5 now and will comment if the problem is gone in the update.

EDIT: Just updated to 3.5 and the problem persists.

Crashes are always bugs. Unity should never crash. We’ll appreciate a bug report using the bug reporter in Unity.

In the future, no need to ask in the forum if a crash is a bug. It is. Just go right ahead and report it so we can track it and look into it. Thanks.

Sent a bug report. For the interested: the bug can be boiled down to trying to make a prefab of an instantiated gameObject.

1 Like

for people having this kind of issue, i deleted the .meta by backuping as a .meta_old (i could have deleted it also) then i came back in my Editor now the prefab opens well (it was corrupted and unable to open the prefab before this) i think Unity regenerating the .meta can solve some issues (my editor crashed just before this)