godot: Add documentation on how to fix corrupt UIDs in a project (workaround inside)

Godot version

4.0 dev

System information

all

Issue description

In some projects and others people are reporting this issue:

WARNING: res://object.tscn:4 - ext_resource, invalid UUID: uid://somebrokenuid- using text path instead: res://assets/models/somepath.tres
     at: load (scene/resources/resource_format_text.cpp:448)

I believe it’s a bug between our alpha and beta godot version, we should fix it, as it appears to not just be The Mirror that has the bug.

A workaround I found I would like to share

I found a working fix for this which can resolve the problem for an entire project, its quite slow to do, but it has worked in our case to clear up all our UID issues. (this goes without saying but I’ll say it: MAKE BACKUPS before you do this)

  1. Use a regex find and replace (in my case I used CLion with the regex box checked) to remove all the UIDs with a space at the start of uid:// (ENSURE you keep the space at the start of uid= regex pattern)
 uid=\"uid://.*?\"
  1. Then use this pattern without the space to nuke it from all the other places its used (ensure no space at start of regex pattern)
uid=\"uid://.*?\"
  1. Open the engine with your project.
  2. Set message queue to a very large size (required for large projects) - I used 819200kb because memory is cheap. image
  3. Reboot editor and project
  4. File -> Quick Open -> Select all scenes with shift select the top and bottom for all scenes.
  5. Wait about 5 minutes until all the scenes open.
  6. File -> Save all scenes
  7. You’re not done yet.
  8. Open the file browser -> Search for all .tres files
  9. Click each .tres individually and click the save icon individually for each file (this took me ages but it worked)
  10. Now it’s important, repeat step 8 again
  11. You should have a bunch of changes to .import/.tres reboot your editor and check for any UID errors in the console they should be gone.

Steps to reproduce

Unsure how the bad UIDs were introduced but they seem to disappear by doing my workaround.

Minimal reproduction project

No response

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 28 (19 by maintainers)

Commits related to this issue

Most upvoted comments

Thanks for the workaround. Here is an improved method that works on git bash or any unix shell in windows or linux. This will find all tscn files, run perl to search and replace on the file to strip out UIDs.

$ find . -name \*.tscn -exec perl -i -pe 's/ ?uid=\"uid:\/\/[a-zA-Z0-9]+?\"//g' {} \;

You can change perl -i to perl -i~ and it will leave a backup copy of the files named .tscn~. If using git, that is unnecessary. I only had UID problems with tscn files. If you want to also get .tres files you can change it above and run it twice, or change the part before exec: find . -name \*.tscn -o -name \*.tres

@Lippanon manually save your scenes as tscn, then revert. Or leave them as tscn. You should be using git, even as a solo dev, and things that change all the time like scenes will both fill up your git server, and not allow you to review your changes before committing. I recommend using git and tscn, tres, no .material, .scn. Only use binary files for things that will not change, such as glb and texture files.

I was able to workaround the issues with my subresource IDs.

We learned today that UIDs are for external files, and have likely been fixed. However you may need to strip out all UIDs in all scenes and resources and let Godot generate new ones using the workarounds in this ticket.

Subresource IDs are for resources saved in the scene file. Godot regenerates new IDs for them on every save. This problem should be fixed in the engine by reusing the same ID on resources that haven’t changed. However, I was able to work around them on my project with the following.

External resources marked “resource_local_to_scene” I don’t really need this, so I removed the flag. Godot kept re-enabling it on some of my scenes and resources, so getting it to stick was a challenge at first.

Themes My custom theme was generated by importing defaults within Godot then customizing it and saving it as an external file. However, this process will create forever changing IDs as there are a lot of embedded icons and widget textures that get included. I went through my file and identified the resources that included textures saved in the file. Fonts, icons, and styleboxes with textures. Then I went through the theme editor and deleted the imported controls with those elements so my UI will use the embedded defaults. If I want to customize a control that includes a font/icon/stylebox, that item needs to be saved to disk, outside of the theme resource file or it will become a changing subresource.

So far this seems to have addressed everything. Git still reports that Godot has changed line endings on many resources and scenes, so the files show as changed. Though they disappear when staged.

Cc @lesleyrs

You should commit .import files (e.g. icon.png.import), but not the .import (3.x) and .godot (4.x) folders. A minimalist .gitignore file for Godot is just this:

.godot/

I followed this workflow and don’t have any UID problems in my project.

If you experience some UID-related bugs, try making a minimal project that reproduces it.

Commit *.import files.

.import folder in the project is gd3 and can be deleted.

.godot folder in the project contains gd4 local caches and should not normally be committed. It normally can be deleted and everything will be regenerated. If your system can’t generate it, that suggests a problem with your system or your assets. Divide and conquer to find out which asset causes the crash.

However there is a bug #75388 that basically means .godot/global_script_class_cache.cfg must be committed since it doesn’t generate properly in certain instances.

This PR exposes the rename_dependencies() method to ResourceLoader that can remove the non-existing UID paths. #73884

for check_resource in ResourceLoader.get_dependencies("res://MyScene.tscn"):
	if not ResourceLoader.exists(check_resource) and check_resource.substr(0, 4) == "uid:":
		prints("UID missing:", check_resource)
		ResourceLoader.rename_dependencies("res://MyScene.tscn", {check_resource:""})

Renaming the UID path to an empty string seems to cause the UID reference to be completely removed from the external reference, replacing it with the path instead.

You can preferably pass the Dictionary argument with all of the bad UID’s in a single call.

This gives a clue as to what’s happening to cause the invalid UID errors: the get_dependencies() call only returns the UID path if it exists in the external reference text, and skips the path name.

I wonder why get_dependencies can’t check to ensure it returns a valid UID and return the path instead after removing the bogus UID?

@dtesniere Scene B depends on Scene C and vice-versa. You created a cyclic dependency, which is not supported. Seems unrelated to this issue.

AFAIK local_to_scene will duplicate the resource each time a scene is instantiated. We’d need some logic to ensure it happens only once 🤔

This is still a problem, even in 4.0-stable with entirely new UIDs, new cache directories and a new UID database.

I used my command to strip out UIDs: find . -name \*.tscn -o -name \*.tres -exec perl -i -pe 's/ ?uid=\"uid:\/\/[a-zA-Z0-9]+?\"//g' {} \;

Then I used the script below to have Godot automatically load and resave all .tres/res files in the project. It can also work on other file types or specific directories by changing the parameters.

It upgrades the format types for .tres/.res files without having to manually open them and click the save icon one by one.

-[gd_resource type="ArrayMesh" load_steps=2 format=2]
+[gd_resource type="ArrayMesh" load_steps=2 format=3 uid="uid://cr1p1x33ubgn2"]

You could add .tscn to the extensions and see if it will work with that, however in my testing it appears insufficient compared to opening all scenes and saving them.

Create a test scene, attach this script, save, close, and reopen the scene. It will process everything upon reopening, since it’s a tool.

@tool
extends Node


const START_DIR = "res://"
const EXTENSIONS = [ "tres", "res" ]


func _ready():
	process_dir(START_DIR)
	
	
func process_dir(dir_name: String) -> void:
	var dir := DirAccess.open(dir_name)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		if dir_name.ends_with("/"):
			dir_name = dir_name.trim_suffix("/")
		while file_name != "":
			if dir.current_is_dir():
				print("----- New directory: " + dir_name + "/" + file_name + " -----")
				process_dir(dir_name + "/" + file_name)
			elif file_name.get_extension() in EXTENSIONS:
				print("Processing file: " + dir_name + "/" + file_name)
				var res := ResourceLoader.load(dir_name + "/" + file_name)
				ResourceSaver.save(res)
				
			file_name = dir.get_next()
	else:
		print("An error occurred when trying to access the path: ", dir_name)

Hello, I now have the same problem with my update process. This error is really frustrating!

For my use case I have an integrated plugin upgrade tool where a new version is installed when it is available. Since the introduction of this uid the plugin starts after the update with these ominous uid problems

For more background, the uid’s are a kind of cache to reference resources. You have to in account the cache can be deleted, and the uid’s must be regenerate. Means if you delete all imported images rm -rf *.svg.import you will run into this issue.

And important when you deliver a plugin the cached resources are never be part of the plugin and you will run always into this issue.

As example i have a animated texture resource

+[ext_resource type="Texture2D" uid="uid://0d4wn0t2wnq5" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress7.svg" id="1"]
+[ext_resource type="Texture2D" uid="uid://djsa452vjyeg8" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress5.svg" id="2"]
+[ext_resource type="Texture2D" uid="uid://bk7ejnw132eyv" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress1.svg" id="3"]
+[ext_resource type="Texture2D" uid="uid://conhui4b6ubsn" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress8.svg" id="4"]
+[ext_resource type="Texture2D" uid="uid://cgemfcu6qacvx" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress2.svg" id="5"]
+[ext_resource type="Texture2D" uid="uid://bd2ro6pysahsb" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress6.svg" id="6"]
+[ext_resource type="Texture2D" uid="uid://cekd6xs0756i0" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress3.svg" id="7"]
+[ext_resource type="Texture2D" uid="uid://dovxd5j4scybs" path="res://addons/gdUnit4/src/ui/assets/spinner/Progress4.svg" id="8"]
 
 [resource]
 frames = 8
 speed_scale = 2.5
 frame_0/texture = ExtResource("3")

Each included texture (Progress*.svg) has a uid but the uid will never match when you install the plugin at first time.

Please fix this bug as soon as possible, this kind of error is confusing the user.