godot: TargetFramework .NET Standard 2.0+ crashes on launch, can't find assembly System.Text.Json

Godot version:

  • 3.2.3 mono stable
  • 4.0 mono compiled at commit d425cf6fe

OS/device including version: Ubuntu 20.04

Issue description:

Godot 3.2.3 was released and includes PR #41408 which, as I understand, should allow me to change the framework to .NET Standard 2.0 or greater. So I tried changing the framework to netstandard2.1 and found this issue.

The game compiles fine but when launching it, it immediately crashes with the error:

E 0:00:00.509   debug_send_unhandled_exception_error: System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Json, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies.
  <C++ Error>   Unhandled exception
  <C++ Source>  modules/mono/mono_gd/gd_mono_utils.cpp:424 @ debug_send_unhandled_exception_error()

The .csproj is as follows:

<Project Sdk="Godot.NET.Sdk/3.2.3">
  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="System.Text.Json" Version="4.7.2" />
  </ItemGroup>
</Project>

This only happens when changing the framework to netstandard2.0 or netstandard2.1, I have found that both of those throw that error, but if the framework is kept as net472 it works fine. I’m not sure if 3.2.3 is supposed to work well with .NET Standard since the default is still net472 so I tried compiling master as well and got the same results.

Steps to reproduce:

  1. Create a new project
  2. Change TargetFramework to netstandard2.1
  3. Add System.Text.Json package (dotnet add package System.Text.Json)
  4. Launch Game in Editor
  5. Game builds and launches but immediately crashes

Minimal reproduction project: NetStd21.zip

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 2
  • Comments: 15 (9 by maintainers)

Most upvoted comments

It looks like this can be solved if we set CopyLocalLockFileAssemblies to true in our Sdk (it’s disabled by default for .NETStandard projects and non-Exe .NETCoreApp projects). Meanwhile you can add this manually to your csproj:

  <PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

I looked a little into this.

First, it looks like the place Godot/Mono is expecting to find the DLL is .mono\temp\bin\Debug. So the first question is why the package’s DLLs show up there for net472 but not netstandard2.0 / netstandard2.1.

I don’t know the answer. But, adding <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> to a PropertyGroup in the csproj makes them show up.


But with netstandard2.1 there’s still an exception thrown at runtime after that workaround, it just changes. New exception:

Unhandled Exception:
System.TypeInitializationException: The type initializer for 'System.Text.Json.JsonSerializer' threw an exception. ---> System.MissingMethodException: Method not found: int System.Text.Encodings.Web.TextEncoder.FindFirstCharacterToEncodeUtf8(System.ReadOnlySpan`1<byte>)
  at System.Text.Json.JsonEncodedText.EncodeHelper (System.ReadOnlySpan`1[T] utf8Value, System.Text.Encodings.Web.JavaScriptEncoder encoder) [0x00000] in <3e024d1008104aac9fe12198f4c68344>:0
  at System.Text.Json.JsonEncodedText.TranscodeAndEncode (System.ReadOnlySpan`1[T] value, System.Text.Encodings.Web.JavaScriptEncoder encoder) [0x00033] in <3e024d1008104aac9fe12198f4c68344>:0
  at System.Text.Json.JsonEncodedText.Encode (System.ReadOnlySpan`1[T] value, System.Text.Encodings.Web.JavaScriptEncoder encoder) [0x00014] in <3e024d1008104aac9fe12198f4c68344>:0
...

I found this issue about it: https://github.com/dotnet/runtime/issues/1460. The version of System.Memory.dll that ends up at .mono\temp\bin\Debug conflicts with the one provided by Mono, so there are actually two different versions of ReadOnlySpan<byte> loaded that aren’t matching up with each other. (If that issue really does apply to this situation.)

The workaround mentioned in that issue is to add <PackageReference Include="System.Memory" Version="4.5.3" IncludeAssets="None" /> to an ItemGroup in the csproj to make sure that Mono’s version of System.Memory.dll is used. (Note: 4.5.3 is old and causes a build warning–4.5.4 is the new version.) This workaround does make System.Memory.dll disappear from .mono, but the error doesn’t change for me.

Not sure where to go from there. I don’t see any explanation on that thread of how you can actually tell what ReadOnlySpan<byte> implementations are being loaded. 🙁