The issue is, that a dictionary cannot contain the same key multiple times, but when Unity creates a new entry of your list, whenever you resize it in the inspector, it will just copy the last item. In this case, or even if it would create a new empty instance, the key of the entry would be either empty string or the last items key, which causes the dictionary to throw an exception.

To work around this, you can easily use your existing custom editor and instead of copying the last item, create a new one with a unique key.

Here is the complete working code:

    using UnityEngine;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEditorInternal;
    
    public class ResourceManager : MonoBehaviour, ISerializationCallbackReceiver
    {
        private Dictionary<string, Object> resources = new Dictionary<string, Object>();
    
        // Hide this, because it will not work correctly without the custom editor.
        //[HideInInspector]
        [SerializeField]
        private List<ResourceEntry> entries = new List<ResourceEntry>();
    
        // Dictionary -> List
        public void OnBeforeSerialize()
        {
            entries.Clear();
            foreach (KeyValuePair<string, Object> kvp in resources)
            {
                entries.Add(new ResourceEntry(kvp.Key, kvp.Value));
            }
        }
    
        // List -> Dictionary
        public void OnAfterDeserialize()
        {
            resources.Clear();
            foreach (ResourceEntry entry in entries)
            {
                resources.Add(entry.key, entry.value);
            }
        }
    
        [System.Serializable]
        public class ResourceEntry
        {
            public string key;
            public Object value;
    
            public ResourceEntry() { }
    
            public ResourceEntry(string key, Object value)
            {
                this.key = key;
                this.value = value;
            }
        }
    }
    
    [CustomEditor(typeof(ResourceManager))]
    public class ResourceManagerEditor : Editor
    {
        private ReorderableList list;
    
        public void OnEnable()
        {
            list = new ReorderableList(serializedObject, serializedObject.FindProperty("entries"), true, true, true, true);
            list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
            {
                SerializedProperty element = list.serializedProperty.GetArrayElementAtIndex(index);
                rect.y += 2;
                EditorGUI.PropertyField(new Rect(rect.x, rect.y, 60, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("key"), GUIContent.none);
                EditorGUI.PropertyField(new Rect(rect.x + 70, rect.y, 160, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("value"), GUIContent.none);
            };
    
            list.onAddCallback = (ReorderableList list) =>
            {
                int index = list.serializedProperty.arraySize;
                list.serializedProperty.arraySize++;
                list.index = index;
    
                // Important! When adding a new element to the list (and dictionary),
                // the newly created key must be unique.
                SerializedProperty element = list.serializedProperty.GetArrayElementAtIndex(index);
                element.FindPropertyRelative("key").stringValue = System.Guid.NewGuid().ToString(); // Create some kind of unique key, like a GUID or adding a number to the last one.
            };
        }
    
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            list.DoLayoutList();
            serializedObject.ApplyModifiedProperties();
        }
    }


The only change that matters to your specific question is the "onAddCallback" in the custom editor. There you can change the way Unity creates a new list element and give it a unique key at initialization. Remember, you can still edit the value in the inspector, but should make sure that the user doesn't enter a key, that already exists somewhere else.