Undo.RecordObject doesn't work

Hello fellows!

I’ve watch several threads about this topic, but none of the solutions works for me :frowning:

I just want to create and edit an Object via an editor window, and make ctrl+z works if I change it. I don’t mean a GameObject, just and Object. This is my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class UndoLearning1 : EditorWindow {
	Tree newTree = new Tree();

	[MenuItem ("Tools/Undo Learning 1")]
	public static void Init(){
		UndoLearning1 myWindow = (UndoLearning1)EditorWindow.GetWindow(typeof (UndoLearning1));

	 void OnGUI(){
		if (GUILayout.Button("Create Branch")){
			Undo.RecordObject(newTree, "Branch Added");
			newTree.branchs.Add(new Branch());

	 void Update(){

public class Tree : Object{
	public List<Branch> branchs = new List<Branch>();

public class Branch{
	public List<Vector3> points = new List<Vector3>();

When I hit ctrl+z after “Create Branch” button, the console says “Undo object may not be null.” But the Debug.Log works fine and logs what it should.

What’s wrong with this code?

Thanks for your time!

This is just a hunch. But I believe that your problem may be due the fact that Branch is not set as serializable. Try using the the [System.Serializable] attribute on the Branch class.

I had a problem similar to this earlier where I was modifying a private member variable through a property. Private variables are not serialized by default in unity so I had to tell unity to both serialize it and hide it in the inspector using attributes ([SerializeField] and [HideInInspector])

I found this post by complete accident:

quoting it in case it’s deleted:

Undo.RegisterCompleteObjectUndo(Object objectToUndo, string name) will record a copy of the full state of the object that it will keep, unlike Undo.RecordObject(Object objectToUndo, string name) that will only keep a
copy of the state until the end of the
frame to compute a diff.
By the way, I just got the following
error that drove me to find more on
this method:

Generating diff of this object for
undo because the type tree changed.
This happens if you have used
Undo.RecordObject when changing the
script property. Please use
So RegisterCompleteObjectUndo seems important in complex situations were a diff is not possible.

Couple of words from myself:

Undo.RegisterCompleteObjectUndo seems to work with Event and editor-GUI as well every time. And RecordObject seemed only to work sometimes (only worked occasionally)

Additionally, if you are working with Event in editor script, and actually have code that Use()s the GUI event, chances are the event might not get through to unity’s undo system.
You might need to call Undo.FlushUndoRecordObjects(); after RegisterCompleteObjectUndo()


Don’t forget to use EditorUtility.SetDirty() on the object, AFTER you’ve recoreded into Undo

Here is an example, allowing me to offset 2D viewport up/down left/right:

void DragViewingArea() {
            int id = GUIUtility.GetControlID(6, FocusType.Passive);
            //prepare for drag:
            if (_currentEvent.type == EventType.MouseDown && _currentEvent.button == 2) {
                Undo.RegisterCompleteObjectUndo(_fsm, "begin drag FSM viewport on " + _fsm.gameObject.name);
                GUIUtility.hotControl = id;
            if(_currentEvent.type == EventType.MouseDrag && GUIUtility.hotControl == id) {
                _fsm._fsmEditorWindow_TableOffset += _currentEvent.delta;
                EditorUtility.SetDirty(_fsm); //set dirty as soon as we actually drag
            //finished dragging
            if (_currentEvent.type == EventType.mouseUp  &&  _currentEvent.button == 2  &&  GUIUtility.hotControl == id) {
                GUIUtility.hotControl = 0;

Perhaps try using Undo.RegisterCreatedObjectUndo instead

I know this has been a while but i came across this trying to fix my issue now with doing undo on a scriptable object.

Turns out i had to make my variable public and then undo.recordobject worked as expected.

It did not work when my variable was protected with public property getter/setter.