Source file not found when any script is added, deleted, or renamed after syncing with source control

Explanation:

Unity will fail to compile scripts with an error like:

error CS2001: Source file 'E:\Projects\Unity\Projects\Empty2022\Assets/TestNewFile2.cs' could not be found.

This happens the most consistently with batchmode, which our build CI is constantly failing against.

Myself and others on the team also encounter this issue in our main project when syncing version control with the editor open, although it is less consistent. Restarting the editor always fixes it.

Syncing source control frequently introduces new, deleted, or renamed scripts, so this happens often enough to be disruptive to our workflow.

Repro Steps:

The most consistent way to reproduce:

  1. Create empty project
    (For reference, when I say empty project, I mean I create an empty folder with only “Assets” and “ProjectSettings” folders inside it, then opening that as a project in Unity Hub.)

  2. Add a script file in editor

  3. Close editor

  4. Rename the script file and the .meta and class name in the file to match.

  5. Open a terminal in the project root

  6. Open the project in batchmode: C:\path\to\Editor\Unity.exe -batchmode -projectPath ./ -quit

If I run the same command a 2nd time, it works.

As mentioned above, this can also happen with the editor open, but it is less common.

I also tested with engine version 2022.3.15f1 and was still able to reproduce the error using batchmode.

I made a bug report, but I figured I would ask here as well.

You need to be cautious with that! Doing this can be rather problematic if, for instance, you start to pull changes in the VCS application and while it is pulling changes, you go back to the editor before its finished. Unity may then refresh the current state of assets, with some being at their latest versions and others still being updated.

In the end, at the very least, you may be forced to restart the editor anyway, or you may have to delete the Library folder, or in the very worst case (depending on editor scripts that may do postprocessing and modify assets) the local copy of the project may be corrupted - you’ll see this if the VCS shows unexpectedly modified files after the pull.

See above. :wink:

My hunch is that this is not an actual bug but the workflow of synching changes “live” into a project.

What is the VCS and CI system that you use? Is asset Auto-Refresh disabled for some or all devs?

Odd but perhaps the first run does the asset refresh only after it caused an error, and the next run now works with correctly refreshed assets. Keep in mind that you manually renamed the files on disk outside of Unity. Still, compilation should happen only after the AssetDatabase was refreshed.

Hi I’m another dev on the team. Here’s some more context:

  • We use Perforce for VCS and TeamCity for CI. I think all devs have auto-refresh enabled.
  • We’ve been using Unity for 2 years. Syncing while the editor is open has been working until recently. It’s a feature that actually really impressed us about Unity. I thought this issue didn’t start happening until after upgrading to Unity 6, but Travis is seeing the CI issue in 2022 so :person_shrugging:
  • We are experiencing 2 issues, one with devs and one with CI. They seem very similar so we are assuming they are related.
  • The dev issue is after syncing and then the auto-refresh, there are no compile errors in the console, however scripts that were moved or renamed by another team member show up as “missing” in the inspector. Simply restarting Unity fixes it.
  • When this started happening, we started to get in the habit of closing Unity, syncing, then reopening Unity. However the issue can still occur even when doing that. We have to close Unity, sync, open Unity, close Unity, open Unity again.
  • One more symptom is when using ParallelSync. My local Unity can be doing fine, then when I tell ParallelSync to open the clone, the clone will 100% of the time spew a bunch of errors on load about missing MonoBehaviours related to moved or renamed scripts. I have to close the clone, then tell ParallelSync to open the clone again and then everything is fine. I know this isn’t a Unity product, just mentioning in case it’s helpful for diagnosing. I didn’t see this issue with ParallelSync until after upgrading to Unity 6.

Unity scans for files periodically, such as when you return focus to it, etc.

The rules used to be super-simple so you could confidently use source control and Unity wouldn’t scan for files until it became focused.

Unfortunately that has changed and now before you even give it focus, sometimes Unity can start scanning files (not always, but very often) and thus get ahead of your source control and start trying to consider moved scripts and produce new .meta files for them, which will break all linkages.

The only true cure is going to be to shut Unity when doing any transactions with project files, allowing 100% of file syncing to finish. This is sub-optimal, so most of us just deal with the random need to periodically reset files from source, reimport entire subdirectories, etc.

Do you know when that was changed, or why that can occur?
I currently have auto-refresh disabled in all Unity 6 projects under source control, that may explain why I haven’t experienced that behaviour recently.

Like Kurt indicated, part of this smells like a “meta out of sync” issue. But these don’t fix themselves when restarting the editor.

I once created a server-side hook script on Perforce to disallow committing any file under /Assets without also committing the file’s .meta file in the same commit - those would lead each machine to generate its own GUID for that particular asset. Most commonly found with art assets, eg texture or mesh saved/exported to Assets but Unity was not open or not focused before committing. Though it’s hard to imagine how this could happen with scripts or lead to temporary compile errors.

I doubt this is your problem but it can’t hurt to scan recent commits for changing .meta files all by themselves, with the diff showing that the GUID has changed. These you need to fix anyway or their references will keep breaking depending on who pulls when or who drags a reference to an Inspector field.

Have you tried deleting the Library on affected systems to see if this affects the post-sync behaviour?
I suppose CI is set up to always work off of a clean, empty directory? If not, it should be if possible or at least a separate, longer-running (nightly) CI task should do a complete clean pull so that the Library gets rebuilt. Sometimes you won’t spot an issue without cleaning the Library, but more commonly you’ll find an issue in CI that is due to a stale artifact in the Library. Still, both cases are rare but when they occur it’s headscratch time.

Do you have any symlinks in your project? Those also affect how Unity scans for assets.

Everyone (and CI) is working with the exact same editor version down to the patch level? While rare it does pose risks if some devs work with xxxx.x.29f1 and others use .30 and .31 and so forth. It gets worse if you bunnyhop versions, especially downgrading is unsupported and when you do it eg for analysis it warrants deleting the Library for sure.

With Unity 6 you can ditch ParallelSync and use Multiplayer Playmode instead. This is far more convenient, less resource intensive and generally faster.

I wish I did… it’s weird. Even on a single computer with a single version of Unity, inside the same simple project, sometimes it notices changes, sometimes it doesn’t. Twiddling the domain reload and/or auto-refresh settings doesn’t seem to make a reliable change in behaviour, at least not over the term of a week.

The black-box sensation is that Unity sometimes polls the filesystem for changes while it is not in focus, and sometimes it notices very quickly, sometimes I can alt-tab back to Unity before it notices.

I’ve been 99% MacOSX Unity for a decade now, but the last months I’ve been 90% Windows with Unity6 and seeing this same and other irregular notice-changes behaviors.

On MacOSX my version control has always been git, outside of Unity, so very unintrusive. On Windows I’m running p4 Helix Core, which also has its own cadence of opening the auth server website every few minutes, separate auth attempts for Unity itself versus the launched IDE (in this case Visual Studio).

So yeah… just… loose wiggly teeth every day, especially since I’m using Addressables in Unity6… and I do still have one old devbox running Unity5 so I am regularly reminded about how fast and flawless it used to be just a short while ago, alas.

I wonder, do you have the Multiplayer Playmode package installed? Just a hunch because the virtual editors need to interact with the main editor as they share large portions of the assets. Perhaps this package alters the refresh behaviour in general. Or the change was made to accomodate this package since technically only one of these players will be in focus but they all need to pick up changes in the main editor.

I haven’t used Unity recently and don’t work with multiple people on the same project. But using AssetDatabase.StartAssetEditing should still work I guess. It should prevent Unity from importing anything until you call AssetDatabase.StopAssetEditing again. It may be a bit cumbersome to always execute this. Though maybe the source control update can be triggered by a script from inside the Unity editor. Though a small Editorwindow with two buttons to block / unblock shouldn’t be that difficult to remember unless you need to update like 100 times a day.

When doing batch mode stuff on a freshly modifed / updated project, do you call AssetDatabase.Refresh with ImportAssetOptions.ForceSynchronousImport before you do anything else? Of course script changes could still cause issues, but it’s worth a shot.

I wonder if you should rather use DisallowAutoRefresh for such a use case. Start/Stop editing may do more than what’s necessary, I suppose disabling the refresh is just one aspect of it.

Also note that the scripted disallow auto-refresh is different and independent from the corresponding project setting. So if you have the autorefresh setting disabled but call AllowAutoRefresh this won’t enable that setting and the behavior won’t change.

Also worth considering that an editor script may call AssetDatabase.Refresh while the editor is unfocused. Just a theory but I can imagine this to happen if such a script hooks into events outside of Unity, such as .NET file system change events (I recall some example scripts posted here doing something like that).

1 Like

Have you tried deleting the Library

Yes

part of this smells like a “meta out of sync” issue

No I don’t think so. It’s not an issue with the source files on disk. It seems like a caching problem in Unity.

Do you have any symlinks in your project?

No

an editor script may call AssetDatabase.Refresh while the editor is unfocused

I don’t think this is an issue with Unity refreshing while source control is syncing. No compiling or assembly reload starts to happen until focusing Unity. Also we’re a small team so a sync from perforce usually takes less than a second. It’s finished before we could even switch back to Unity. Plus out of habit I don’t switch back to Unity until the sync is finished.

What about the versions? Which one are you using and is everyone using the exact same editor version, including the CI system? If you haven’t try updating to the latest 32f1 patch release, more so the older the patch release you currently work with.

Since you use Perforce there is no commonly established .gitignore equivalent. Could you tell us what the ignore specs for the project looks like?
Most importantly, it is crucial to exclude the Library and Temp folders from source control but also a couple others that are unnecessary (obj, logs, builds, …).

Thanks everyone for your suggestions so far.

Editor Versions

I can confirm CI and the editor versions are the same. Unity is pretty good about complaining when you try to mix editor and project versions.

We were originally on 2022.3.15f1 before this behavior started.
Our initial upgrade to Unity 6 was with 6000.0.23f1. We later upgraded to 6000.0.28f1 in hopes that it would help.

I just tested through the CLI again in .32f1 and am getting the same failure.

.p4ignore

### Unity ###
/Assets/AssetStoreTools*
/Assets/UserSettings/
/Assets/UserSettings.meta
/Build/
/Builds/
/Library/
/Logs/
/MemoryCaptures/
/Recordings/
/Temp/
/Obj/
/UserSettings/

sysinfo.txt

### Random OS Stuff ###
.DS_Store

### Builds ###
*.apk
*.aab
*.unitypackage
*.app

### IDE's ###
.vs/
.vscode/
.idea/
/Assets/Plugins/Editor/JetBrains*

### Project Files ###
*.sln
*.csproj
*.user

### Shared Assets ###
/Assets/SharedAssets/

### WWise ###
/*_WWiseProject/.cache/
/*_WWiseProject/*.prof
/*_WwiseProject/*_WwiseProject.*.validationcache
/*_WwiseProject/*_WwiseProject.*.wsettings
/*_WwiseProject/**/*.akd

# Build temp dir
/Assets/StreamingAssets/

# WWise Picker (editor)
# from https://www.audiokinetic.com/library/edge/?source=Unity&id=unity__troubleshooting.html
# >> Do not keep AkWwiseProjectData.asset under version control! 
# >> This is a temporary cache file for the Wwise project data, 
# >> so as to avoid having the Wwise Picker continuously parse the Work Unit files.
/Assets/Wwise/Editor/ProjectData/AkWwiseProjectData.*

packages

do you have the Multiplayer Playmode package installed?

Also worth considering that an editor script may call AssetDatabase.Refresh while the editor is unfocused.

The project I’m running the CLI from has no packages installed. None of the scripts would be running anyway as the compiler error happens on startup.

Example

Here is a the full log of the command:
Editor.txt (52.5 KB)

I had renamed TestNewFile00.cs to TestNewFile01.cs just before running this.

What’s interesting is that the 1900b0aE-inputdata.json file passed to bee_backend.exe has the most recent filename (TestNewFile01.cs) when I look at it after the CLI has run. So this feels like some caching issue, or a race condition in regards to that program. Like its reading an old version of the file before it is updated by unity.

The Tundra log (tundra.log.json.txt (65.2 KB)) looks like everything runs in order:

{"msg":"inputSignatureChanged","annotation":"WriteText Library/Bee/artifacts/1900b0aE.dag/Assembly-CSharp.rsp" ... Assets/TestNewFile01.cs ...
...
{"msg":"runNodeAction","annotation":"Csc Library/Bee/artifacts/1900b0aE.dag/Assembly-CSharp.dll (+2 others)","displayName":"Compiling C# (Assembly-CSharp)","index":4}

I haven’t really looked at any of these tools before, so I’m not really sure what I would be looking for either.

Anti-virus test

After trying to google tundra and bee_backend errors, I couldn’t find anything similar. Some people reported fixes after disabling their anti-virus. I tried adding an exception to Windows Defender for the project folder, still fails. I even tried disabling anti-virus completely, but still failed.

I can’t recall, is Perforce case sensitive or is this perhaps configurable? Just a thought because gitignore usually does it so that both common cases are ignored: [Bb]uilds

I also noticed that you ignore some folders under /Assets:

For something like user settings and AssetStore tools this should be fine. I’m not so certain about the SharedAssets. If these are being used somewhere within the project they should not be excluded. If they are not used they shouldn’t be in the project in the first place.

If on the other hand the project includes a script that pulls in “shared assets” from a common location then this might explain the one-time compile errors. Suppose the project opens without the (latest) SharedAssets. These supposedly get pulled in with a InitializeOnLoad(Method) attribute code but at this point compilation would already have completed and a missing or out of date SharedAsset script could cause the initial compile error.

Generally speaking: do you have any init-on-load code that modifies the project’s assets, or runs external processes like a batch script that may modify the contents under /Assets?

Even more curious is the exclusion of the StreamingAssets folder. If you use StreamingAssets then this should be under source control. It is definitely not, as the comment indicates, a “build temp dir”!

Only exceptions I see is if you use StreamingAssets to store large videos (or other large files) that are optional and only needed in a build. In that case, I would prefer excluding specific files or a subfolder rather than all of StreamingAssets because it may eventually get used for other purposes too, eg a config file.

I know there is workspace caching in p4 somewhere.

This means if you just change the case of a filename, adding it back will do the wrong thing.

You have to delete the file, then remove it from workspace, then add it back in with the correct case… check the docs for how to do a sequence like that… it takes a few tries to get the hang of it usually.

I don’t recall why /Assets/SharedAssets/ was added to the ignore file, but in our latest we don’t actually have a SharedAssets folder under Assets

I also don’t know why /Assets/StreamingAssets/ was added, we should remove that, but currently the only file in that folder is a desc.txt whose contents explain that file exists just to make sure the folder exists so WWise doesn’t throw a missing folder exception.

Also I believe Travis mentioned above, this can be reproduced in a completely blank Unity project.

I have a repro for this in an empty project. Unity is unable to load a script if the script was renamed while Unity was closed. To get the script to load you have to open Unity, close Unity, then open Unity again.

  • Create a new Unity project
    • Unity 6000.0.28f1
    • Universal 3D template
  • Create a MonoBehaviour TestComponent
  • Create a Prefab TestPrefab
  • Add a TestComponent to TestPrefab
  • Close Unity
  • Rename TestComponent to TestComponent2
    • Rename the class
    • Rename the .cs file
    • Rename the .meta file
  • Open the Unity project again
  • View TestPrefab in the inspector
    • Where the script should be, it says The associated script can not be loaded
  • Close Unity
  • Open the Unity project again
  • View TestPrefab in the inspector
    • The script is correctly loaded now

I filed a bug report with Unity. I’m really surprised this repro’s in a fresh project. Seems like something that would be affecting anyone working in a team.

1 Like

Great!

What happens if you press Ctrl+R (or: RMB => Refresh) at this point?

Is auto-refresh assets disabled in Preferences?

You do understand that manually modifying asset files outside of Unity or the IDE should not be done? Doing so is highly unusual and not recommended, hence it would actually be very rare to …

… be affecting anyone working in a team.

:wink:

But nevertheless, Unity shouldn’t exhibit this behaviour. However I have doubts that this is reproducable. Have you tried doing the same sequence on another machine?

I might try myself later because this got me curious.

I can reproduce the behaviour in 6000.0.32f1. Specifically the missing script warning, and that it works again after re-opening the project.

I also tried Ctrl+R and Reimport of the prefab but that didn’t fix it. Furthermore, I noticed I couldn’t even select the TestComponent2.cs script in the Project View until after I re-opened the project.

I could only select the prefab:
image

Yep that’s exactly the behavior. Thank you for taking the time to repro.

Yes, I use the IDE (Rider) to rename the file so it renames everything for me. And it doesn’t matter if you use Unity to rename, because if one team member uses Unity to rename, another team member will see this issue when they get latest from version control.