16 April 2015
Recently, I’ve had an issue with Unity spewing out one of these errors every time I try to generate my Visual Studio project using Unity VS. Of course, this caused the project file generation to fail.
ArgumentException: Illegal characters in path.
System.IO.Path.IsPathRooted (System.String path) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.IO/Path.cs:508)
SyntaxTree.VisualStudio.Unity.Bridge.ProjectSystem.UnitySolutionBuilder.<CreateSolution>b__2 (System.String a)
System.Linq.Enumerable+<CreateWhereIterator>c__Iterator1D`1[System.String].MoveNext ()
System.Linq.Enumerable+<CreateWhereIterator>c__Iterator1D`1[System.String].MoveNext ()
System.Collections.Generic.List`1[System.String].AddEnumerable (IEnumerable`1 enumerable) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/List.cs:128)
System.Collections.Generic.List`1[System.String]..ctor (IEnumerable`1 collection) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/List.cs:65)
System.Linq.Enumerable.ToArray[String] (IEnumerable`1 source)
SyntaxTree.VisualStudio.Unity.Bridge.ProjectSystem.UnitySolutionBuilder.CreateSolution ()
SyntaxTree.VisualStudio.Unity.Bridge.ProjectSystem.UnitySolutionBuilder.CreateSolutionFromAssetDatabase ()
SyntaxTree.VisualStudio.Unity.Bridge.ProjectFilesGenerator.GenerateProject ()
SyntaxTree.VisualStudio.Unity.Bridge.Project+<>c__DisplayClass3.<RunOnceOnUpdate>b__2 ()
UnityEditor.EditorApplication.Internal_CallUpdateFunctions () (at C:/buildslave/unity/build/artifacts/generated/common/editor/EditorApplication.gen.cs:268)
and
ArgumentException: Illegal characters in path.
System.IO.Path.GetExtension (System.String path) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.IO/Path.cs:255)
UnityEditor.VisualStudioIntegration.SolutionSynchronizer.GenerateAllAssetProjectPart () (at C:/buildslave/unity/build/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs:183)
UnityEditor.VisualStudioIntegration.SolutionSynchronizer.Sync () (at C:/buildslave/unity/build/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs:171)
UnityEditor.SyncVS.SyncVisualStudioProjectIfItAlreadyExists () (at C:/buildslave/unity/build/Editor/Mono/SyncProject.cs:117)
I deleted the Library/assetDatabase3 file to force Unity to rebuild the asset database. This fixed the problem.
So I searched online for solutions to this problem and found nothing that would help me. I tried reinstalling and reimporting Unity VS. I tried different versions of UnityVS - Visual Studio 2012 and 2013. I tried changing build targets from Android to Windows Phone and back again. I tried restarting Unity a few times (but now that I think about it, I’m not sure I tried restarting my PC until after I’d solved it. I wonder if that would’ve solved the problem).
Eventually I stumbled upon a decompiled source code for Unity’s Visual Studio integration (decompiling the DLL of the exception’s source - something I also didn’t think of. Doh!). From here, I was able to navigate to like the GenerateAllAssetProjectPart() method as seen in the second exception.
From here, I was able to locate the call to Path.GetExtension and the parameter that was breaking it.
string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();
for (int i = 0; i < allAssetPaths.Length; i++)
{
string text = allAssetPaths[i];
string extension = Path.GetExtension(text);
*snip*
Ok, GREAT! Now all I have to do is find out which asset has funky characters in it. To do this, I just write some code to do the same call as above and log the filename of any failed paths.
var allAssetPaths = AssetDatabase.GetAllAssetPaths();
for (int i = 0; i < allAssetPaths.Length; i++)
{
string assetPath = allAssetPaths[i];
try
{
string extension = System.IO.Path.GetExtension(assetPath);
}
catch (Exception ex)
{
Debug.Log("Failed asset path: " + assetPath);
}
}
Finally! Some progress. Unity prints out 4 innocent looking filenames.
Assets/Universal Sound FX/MUSIC EFFECTS/Solo Orchestral Brass/MUSIC EFFECT Orchestral Brass Positive 16 (stereo).wav
Assets/3DForge/Fantasy_Interiors/Villages_&_Towns/Prefabs/Props/Lighting/Candles/fi_vil_light_candle03_lit.prefab
Assets/3DForge/Cave Adventure kit/Prefabs/Rock/Moss/Stalactite & stalacmites/moss_stalacmite_thin2_smooth.prefab
Assets/3DForge/Fantasy_Interiors/Villages_&_Towns/Meshes/Props/Library/Clusters/fi_vil_library_book_cluster_small04.fbx
These filenames look fine! What could possibly be wrong with them?! Let’s take a closer look at the paths that make it to the exception block. This code will print out the index of the invalid character as well as the character itself.
var invalidChar = assetPath.IndexOfAny(System.IO.Path.GetInvalidFileNameChars().Where(c => c != '/').ToArray());
if (invalidChar > -1)
{
Debug.Log("Failed Asset Path chars: " + invalidChar.ToString() + assetPath[invalidChar]);
}
Ready for what it looked like? It looked like this.
Yep, it looked like that, nothing.
In hindsight, I probably should’ve grabbed the character code to know for sure but I assume it was some kind of new line character. So from here, the solution was simple. I just had to rename the files… except that didn’t work. When I ran my script again, the exact same, non-renamed filenames were being printed out again.
I assumed there was some sort of caching somewhere (that always seems to be the problem when the data doesn’t match the output). I tried a number of things to clear the cache such as restarting Unity and changing platforms. I even deleted the files to try and get a resolution (they were in source control anyway).
Nothing worked.
So I started poking around the Library folder which is generated by Unity in the project’s root folder. In there was a file named Library/assetDatabase3. So I thought, “I’ll hide that little fella to try and force a cache refresh” by renaming it. There’s a good reason why Unity caches the asset DB; It takes a LOOOOONG time to regenerate. I left it running overnight.
In the morning, I tried to re-generate the VS solution and I received a new error. ACCESS DENIED. A quick online search led me to the solution: “Restart your PC”. Ah the glorious “turn it off and on again”.
That fixed my final hurdle and now I’m up and running with Visual Studio again.
finally
, no more exceptions.
GitHub and Bitbucket now both have support for Git Large File Storage or Git LFS. Basically, this implementation...
I'm a software developer by profession with a wealth of both dev management and programming experience.
My programming background is varied and includes .NET, C#, Node JS, React, Flavours of SQL, Xamarin and Unity among other things.
I spend a great deal of my spare time doing game and web development, writing music and relaxing with my family.
Ping me on Twitter: @panetta