Repository: godotengine/godot (language: cpp)

Issue:
Resources saved to file from an imported scene do not save with consistent UIDs
### Godot version

v4.0.beta.custom_build [98e0d5995]

### System information

Fedora 36

### Issue description

If "save to file" is enabled for meshes or animations in an imported scene, the saved resources are given a random UID if the file doesn't already exist.
This is annoying if you've `.gitignore`d these files, which makes sense to do since they're auto-generated from glTF files. For example, I did so for the vehicle meshes in the [Truck Town](https://github.com/godotengine/godot-demo-projects/tree/4.0-dev/3d/truck_town) demo. If you clone this repo right now, opening any of the vehicle scenes gives multiple invalid UID errors because when the mesh `.res` files are generated they don't get the same UIDs.

I don't know how UIDs work, but I assume the way to fix this would be to remember what UID the resources are saved to in the glTF's `.import` file? That way it would be generated with the same UID every time.

### Steps to reproduce

1. Save a mesh or animation resource from a scene to a file using the advanced import options
2. Reference that resource in a scene and save it
3. Delete the resource and reimport the scene to regenerate it
4. Open the scene referencing the resource, notice the invalid UID error

### Minimal reproduction project

https://github.com/godotengine/godot-demo-projects/tree/4.0-dev/3d/truck_town


Discussion / hints:
Related https://github.com/godotengine/godot/issues/62258
I'm having this problem in 4.1.1 and it's causing me to lose work. Once these warnings have appeared, the next time you open your project, references in resources affected will be missing entirely. This has caused models to go missing, which have to be reassigned in the scenes they were used in, and materials go missing from those models.

The thing costing me the most time is that for some reason, even though I have external materials (not from the .glb file), those that are referenced in the .glb as "use external" are affected by this issue as well. They lose their reference to the shader they were using, causing all the parameters for that material to be removed, so I have to reconfigure everything on top of reassigning the reference.

This issue seems to be intermittent or at least somewhat random, I had time where it didn't happen, but now it is happening frequently enough to halt development of 3D assets until this bug is resolved. It happens on some models/materials and not on others, there doesn't seem to be a common factor between instances.

Is there a reason this issue is not assigned to a milestone? I know there are other people affected by this issue, here and on the Godot forums. And it seems to have been around in some form on older versions too.
> I'm having this problem in 4.1.1 and it's causing me to lose work. Once these warnings have appeared, the next time you open your project, references in resources affected will be missing entirely. This has caused models to go missing, which have to be reassigned in the scenes they were used in, and materials go missing from those models.

I noticed something similar, but I couldn't figure out how to reproduce it so I didn't open a separate issue.
What was happening in my case was that the meshes were being saved with the same exact UID as the imported scene. So when loading scenes or resources referencing the mesh, it would try to load the scene they came from instead. But you can't assign a PackedScene to a property that expects a Mesh, so it just assigned null without any errors.
To fix it, I removed the line from the `.import` file that stored the UID, then deleted the mesh files, then reimported.



This sounds like a bug that could cause some pretty severe (but possibly rare) problems.
I also noticed that when I tried to use the dependency menu to point towards the right resource instead, setting it just did nothing, but that would make sense if the UID's were the same.

I did find that deleting the mesh imports and re-importing the `.glb` fixed those temporarily. But it seemed to come back quickly. I didn't try deleting the line from the `.import` file, is that the one for the `.glb`?
Unfortunately, this "fix" won't work for my broken materials, as they are not imported from the `.glb`.
I still don't know why those are being broken in the same way, it has to be because of the UID overlap, I'm just not sure what it was overlapping with. I think I remember the shader reference pointing towards the `.glb` or a mesh or something else, but the shader is completely separate to the imported `.glb`.

Not sure what we are supposed to do with the invalid UID warning, as it seems to be able to fallback to the text path, but not allow us to fix the UID's.
> This sounds like a bug that could cause some pretty severe (but possibly rare) problems.

@VentaGhost I can confirm this.
Right now I pretty much cannot properly use git with my project because the .res files will have tons of diffs and it is really bad. If I had any back-end knowledge, I'd immediately go fix it myself, but I do not. :c
@betalars So this issue is still happening in the latest version? I had hoped some of the UID changes that came with 4.2 would fix this. Is this with an existing project from before 4.2 or with a new project created with 4.2? Because I wonder if it's just an issue with your project files. Still very unfortunate there isn't a way to fix this, this bug has basically killed that project I was working on because it kept resetting my materials. Might try importing everything to a fresh project at some point but I'd rather not waste time if the bug still exists.
By any chance are you working on Linux? Because I'd expect more people to have experienced this bug especially with large projects unless it's platform specific?
@VantaGhost there still seems to be an issue, [as demonstrated in this demo project](https://github.com/betalars/godot-uuid-bug) when initialising a new Project in Godot 4.2

In the last commit, something about the res file changes.

Steps to "reproduce":

1. `git clone git@github.com:betalars/godot-uuid-bug.git`
2. open the project in godot
3. `git diff`

However, I think this is actually a new issue, as the UUID included in the scene seems to be consistent.

How I forced this error to happen on my side:
1. I initialised the Repo
2. Added a Suzanne res, umported it to the main scene
3. git commit
4. closed godot
5. deleted .godot
6. re-opend godot
7. suddenly: [a diff](https://github.com/betalars/godot-uuid-bug/commit/b50a8f5ad64fc5d5669691efc49451ae1fd9c115)

@AThousandShips can you try to look into this? I think the [issue I've opened before](https://github.com/godotengine/godot/issues/87614) may be it's own problem.

I use nixos as an OS
Unable to do so right now, someone else might be able to look into it
Update: it is a known issue

Fix patch:
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index 81af2e0543aa..211ee77ca197 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -1303,9 +1303,9 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
 				Dictionary anim_settings = p_animation_data[name];
 
 				{
-					int slices_count = anim_settings["slices/amount"];
+					int slice_count = anim_settings["slices/amount"];
 
-					for (int i = 0; i < slices_count; i++) {
+					for (int i = 0; i < slice_count; i++) {
 						String slice_name = anim_settings["slice_" + itos(i + 1) + "/name"];
 						int from_frame = anim_settings["slice_" + itos(i + 1) + "/start_frame"];
 						int end_frame = anim_settings["slice_" + itos(i + 1) + "/end_frame"];
@@ -1531,8 +1531,26 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
 							if (matdata.has("use_external/enabled") && bool(matdata["use_external/enabled"]) && matdata.has("use_external/path")) {
 								String path = matdata["use_external/path"];
 								Ref<Material> external_mat = ResourceLoader::load(path);
+								if (external_mat.is_null()) {
+									if (matdata.has("use_external/fallback_path")) {
+										String fallback_save_path = matdata["use_external/fallback_path"];
+										if (!fallback_save_path.is_empty()) {
+											external_mat = ResourceLoader::load(fallback_save_path);
+											if (external_mat.is_valid()) {
+												path = fallback_save_path;
+											}
+										}
+									}
+								}
 								if (external_mat.is_valid()) {
 									m->set_surface_material(i, external_mat);
+									if (!path.begins_with("uid://")) {
+										const ResourceUID::ID id = ResourceLoader::get_resource_uid(path);
+										if (id != ResourceUID::INVALID_ID) {
+											matdata["use_external/path"] = ResourceUID::get_singleton()->id_to_text(id);
+										}
+									}
+									matdata["use_external/fallback_path"] = external_mat->get_path();
 								}
 							}
 						}
@@ -1784,13 +1802,14 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
 }
 
 Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, const String &p_save_to_path, bool p_keep_custom_tracks) {
-	if (!p_save_to_file || !p_save_to_path.is_resource_file()) {
+	String res_path = ResourceUID::ensure_path(p_save_to_path);
+	if (!p_save_to_file || !res_path.is_resource_file()) {
 		return anim;
 	}
 
-	if (FileAccess::exists(p_save_to_path) && p_keep_custom_tracks) {
+	if (FileAccess::exists(res_path) && p_keep_custom_tracks) {
 		// Copy custom animation tracks from previously imported files.
-		Ref<Animation> old_anim = ResourceLoader::load(p_save_to_path, "Animation", ResourceFormatLoader::CACHE_MODE_IGNORE);
+		Ref<Animation> old_anim = ResourceLoader::load(res_path, "Animation", ResourceFormatLoader::CACHE_MODE_IGNORE);
 		if (old_anim.is_valid()) {
 			for (int i = 0; i < old_anim->get_track_count(); i++) {
 				if (!old_anim->track_is_imported(i)) {
@@ -1801,16 +1820,21 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani
 		}
 	}
 
-	if (ResourceCache::has(p_save_to_path)) {
-		Ref<Animation> old_anim = ResourceCache::get_ref(p_save_to_path);
+	if (ResourceCache::has(res_path)) {
+		Ref<Animation> old_anim = ResourceCache::get_ref(res_path);
 		if (old_anim.is_valid()) {
 			old_anim->copy_from(anim);
 			anim = old_anim;
 		}
 	}
-	anim->set_path(p_save_to_path, true); // Set path to save externally.
-	Error err = ResourceSaver::save(anim, p_save_to_path, ResourceSaver::FLAG_CHANGE_PATH);
-	ERR_FAIL_COND_V_MSG(err != OK, anim, "Saving of animation failed: " + p_save_to_path);
+	anim->set_path(res_path, true); // Set path to save externally.
+	Error err = ResourceSaver::save(anim, res_path, ResourceSaver::FLAG_CHANGE_PATH);
+
+	ERR_FAIL_COND_V_MSG(err != OK, anim, "Saving of animation failed: " + res_path);
+	if (p_save_to_path.begins_with("uid://")) {
+		// slow
+		ResourceSaver::set_uid(res_path, ResourceUID::get_singleton()->text_to_id(p_save_to_path));
+	}
 	return anim;
 }
 
@@ -2041,6 +2065,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
 		case INTERNAL_IMPORT_CATEGORY_MESH: {
 			r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
+			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/shadow_meshes", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lightmap_uv", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/lods", PROPERTY_HINT_ENUM, "Default,Enable,Disable"), 0));
@@ -2049,11 +2074,13 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
 		case INTERNAL_IMPORT_CATEGORY_MATERIAL: {
 			r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "use_external/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/path", PROPERTY_HINT_FILE, "*.material,*.res,*.tres"), ""));
+			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
 		} break;
 		case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
 			r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "settings/loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Pingpong"), 0));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
-			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
+			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.anim,*.tres"), ""));
+			r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
 			r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
 
@@ -2063,7 +2090,8 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
 				r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
 				r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Pingpong"), 0));
 				r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
-				r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
+				r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.anim,*.tres"), ""));
+				r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/fallback_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), ""));
 				r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
 			}
 		} break;
@@ -2527,7 +2555,7 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
 
 					if (bool(mesh_settings.get("save_to_file/enabled", false))) {
 						save_to_file = mesh_settings.get("save_to_file/path", String());
-						if (!save_to_file.is_resource_file()) {
+						if (!ResourceUID::ensure_path(save_to_file).is_resource_file()) {
 							save_to_file = "";
 						}
 					}
@@ -2581,16 +2609,24 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_
 				src_mesh_node->get_mesh()->optimize_indices();
 
 				if (!save_to_file.is_empty()) {
-					Ref<Mesh> existing = ResourceCache::get_ref(save_to_file);
+					String save_res_path = ResourceUID::ensure_path(save_to_file);
+					Ref<Mesh> existing = ResourceCache::get_ref(save_res_path);
 					if (existing.is_valid()) {
 						//if somehow an existing one is useful, create
 						existing->reset_state();
 					}
 					mesh = src_mesh_node->get_mesh()->get_mesh(existing);
 
-					ResourceSaver::save(mesh, save_to_file); //override
+					Error err = ResourceSaver::save(mesh, save_res_path); //override
+					if (err != OK) {
+						WARN_PRINT(vformat("Failed to save mesh %s to '%s'.", mesh->get_name(), save_res_path));
+					}
+					if (err == OK && save_to_file.begins_with("uid://")) {
+						// slow
+						ResourceSaver::set_uid(save_res_path, ResourceUID::get_singleton()->text_to_id(save_to_file));
+					}
 
-					mesh->set_path(save_to_file, true); //takeover existing, if needed
+					mesh->set_path(save_res_path, true); //takeover existing, if needed
 
 				} else {
 					mesh = src_mesh_node->get_mesh()->get_mesh();
@@ -2868,14 +2904,66 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM
 	return scene;
 }
 
-Error ResourceImporterScene::_check_resource_save_paths(const Dictionary &p_data) {
+static Error convert_path_to_uid(ResourceUID::ID p_source_id, const String &p_hash_str, Dictionary &p_settings, const String &p_path_key, const String &p_fallback_path_key) {
+	const String &raw_save_path = p_settings[p_path_key];
+	String save_path = ResourceUID::ensure_path(raw_save_path);
+	if (raw_save_path.begins_with("uid://")) {
+		if (save_path.is_empty() || !DirAccess::exists(save_path.get_base_dir())) {
+			if (p_settings.has(p_fallback_path_key)) {
+				String fallback_save_path = p_settings[p_fallback_path_key];
+				if (!fallback_save_path.is_empty() && DirAccess::exists(fallback_save_path.get_base_dir())) {
+					save_path = fallback_save_path;
+					ResourceUID::get_singleton()->add_id(ResourceUID::get_singleton()->text_to_id(raw_save_path), save_path);
+				}
+			}
+		} else {
+			p_settings[p_fallback_path_key] = save_path;
+		}
+	}
+	ERR_FAIL_COND_V(!save_path.is_empty() && !DirAccess::exists(save_path.get_base_dir()), ERR_FILE_BAD_PATH);
+	if (!save_path.is_empty() && !raw_save_path.begins_with("uid://")) {
+		const ResourceUID::ID id = ResourceLoader::get_resource_uid(save_path);
+		if (id != ResourceUID::INVALID_ID) {
+			p_settings[p_path_key] = ResourceUID::get_singleton()->id_to_text(id);
+		} else {
+			ResourceUID::ID save_id = hash64_murmur3_64(p_hash_str.hash64(), p_source_id) & 0x7FFFFFFFFFFFFFFF;
+			if (ResourceUID::get_singleton()->has_id(save_id)) {
+				if (save_path != ResourceUID::get_singleton()->get_id_path(save_id)) {
+					// The user has specified a path which does not match the default UID.
+					save_id = ResourceUID::get_singleton()->create_id();
+				}
+			}
+			p_settings[p_path_key] = ResourceUID::get_singleton()->id_to_text(save_id);
+			ResourceUID::get_singleton()->add_id(save_id, save_path);
+		}
+		p_settings[p_fallback_path_key] = save_path;
+	}
+	return OK;
+}
+
+Error ResourceImporterScene::_check_resource_save_paths(ResourceUID::ID p_source_id, const String &p_hash_suffix, const Dictionary &p_data) {
 	Array keys = p_data.keys();
-	for (int i = 0; i < keys.size(); i++) {
-		const Dictionary &settings = p_data[keys[i]];
+	for (int di = 0; di < keys.size(); di++) {
+		Dictionary settings = p_data[keys[di]];
 
 		if (bool(settings.get("save_to_file/enabled", false)) && settings.has("save_to_file/path")) {
-			const String save_path = ResourceUID::ensure_path(settings["save_to_file/path"]);
-			ERR_FAIL_COND_V(!save_path.is_empty() && !DirAccess::exists(save_path.get_base_dir()), ERR_FILE_BAD_PATH);
+			String to_hash = keys[di].operator String() + p_hash_suffix;
+			Error ret = convert_path_to_uid(p_source_id, to_hash, settings, "save_to_file/path", "save_to_file/fallback_path");
+			ERR_FAIL_COND_V_MSG(ret != OK, ret, vformat("Resource save path %s not valid. Ensure parent directory has been created.", settings.has("save_to_file/path")));
+		}
+
+		if (settings.has("slices/amount")) {
+			int slice_count = settings["slices/amount"];
+			for (int si = 0; si < slice_count; si++) {
+				if (bool(settings.get("slice_" + itos(si + 1) + "/save_to_file/enabled", false)) &&
+						settings.has("slice_" + itos(si + 1) + "/save_to_file/path")) {
+					String to_hash = keys[di].operator String() + p_hash_suffix + itos(si + 1);
+					Error ret = convert_path_to_uid(p_source_id, to_hash, settings,
+							"slice_" + itos(si + 1) + "/save_to_file/path",
+							"slice_" + itos(si + 1) + "/save_to_file/fallback_path");
+					ERR_FAIL_COND_V_MSG(ret != OK, ret, vformat("Slice save path %s not valid. Ensure parent directory has been created.", settings.has("save_to_file/path")));
+				}
+			}
 		}
 	}
 
@@ -2940,14 +3028,14 @@ Error ResourceImporterScene::import(ResourceUID::ID p_source_id, const String &p
 	// Check whether any of the meshes or animations have nonexistent save paths
 	// and if they do, fail the import immediately.
 	if (subresources.has("meshes")) {
-		err = _check_resource_save_paths(subresources["meshes"]);
+		err = _check_resource_save_paths(p_source_id, "m", subresources["meshes"]);
 		if (err != OK) {
 			return err;
 		}
 	}
 
 	if (subresources.has("animations")) {
-		err = _check_resource_save_paths(subresources["animations"]);
+		err = _check_resource_save_paths(p_source_id, "a", subresources["animations"]);
 		if (err != OK) {
 			return err;
 		}
diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h
index af79746a4c34..68c06efbabbc 100644
--- a/editor/import/3d/resource_importer_scene.h
+++ b/editor/import/3d/resource_importer_scene.h
@@ -210,7 +210,7 @@ class ResourceImporterScene : public ResourceImporter {
 		SHAPE_TYPE_AUTOMATIC,
 	};
 
-	static Error _check_resource_save_paths(const Dictionary &p_data);
+	static Error _check_resource_save_paths(ResourceUID::ID p_source_id, const String &p_hash_suffix, const Dictionary &p_data);
 	Array _get_skinned_pose_transforms(ImporterMeshInstance3D *p_src_mesh_node);
 	void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
 	Node *_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp
index 71b010a97026..609835385b1e 100644
--- a/editor/import/3d/scene_import_settings.cpp
+++ b/editor/import/3d/scene_import_settings.cpp
@@ -1585,6 +1585,10 @@ void SceneImportSettingsDialog::_save_dir_confirm() {
 			continue; //ignore
 		}
 		String path = item->get_text(1);
+		String uid_path = path;
+		if (path.begins_with("uid://")) {
+			path = ResourceUID::uid_to_path(uid_path);
+		}
 		if (!path.is_resource_file()) {
 			continue;
 		}
@@ -1601,9 +1605,11 @@ void SceneImportSettingsDialog::_save_dir_confirm() {
 					EditorNode::get_singleton()->add_io_error(TTR("Can't make material external to file, write error:") + "\n\t" + path);
 					continue;
 				}
+				uid_path = ResourceUID::path_to_uid(path);
 
 				md.settings["use_external/enabled"] = true;
-				md.settings["use_external/path"] = path;
+				md.settings["use_external/path"] = uid_path;
+				md.settings["use_external/fallback_path"] = path;
 
 			} break;
 			case ACTION_CHOOSE_MESH_SAVE_PATHS: {
@@ -1611,14 +1617,16 @@ void SceneImportSettingsDialog::_save_dir_confirm() {
 				MeshData &md = mesh_map[id];
 
 				md.settings["save_to_file/enabled"] = true;
-				md.settings["save_to_file/path"] = path;
+				md.settings["save_to_file/path"] = uid_path;
+				md.settings["save_to_file/fallback_path"] = path;
 			} break;
 			case ACTION_CHOOSE_ANIMATION_SAVE_PATHS: {
 				ERR_CONTINUE(!animation_map.has(id));
 				AnimationData &ad = animation_map[id];
 
 				ad.settings["save_to_file/enabled"] = true;
-				ad.settings["save_to_file/path"] = path;
+				ad.settings["save_to_file/path"] = uid_path;
+				ad.settings["save_to_file/fallback_path"] = path;
 
 			} break;
 		}


Test patch: