Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

App aborts with "Failed to load AOT module" after a NuGet version change without a clean build

Aperta
#27,044 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@rolfbjarne ci sta già lavorando.

Dal 28/10/2026.

  • #27105 di @rolfbjarne — aperta

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
48/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
csharp, ios

Direzione di ricerca

Start by reading AOTCompile.IsUpToDate in msbuild/Xamarin.MacDev.Tasks/Tasks/AOTCompile.cs and the _CopyResolvedFilesToPublishPreserveNewest behavior in Microsoft.NET.Publish.targets; the issue identifies both timestamp checks. Reproduce with the provided iOS sample by changing the Newtonsoft.Json version and building without cleaning. Done means the rebuilt app matches a clean build after either a package upgrade or downgrade, including its bundled assemblies and AOT outputs.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug
Apple platform

iOS

Framework version

net10.0-* and net11.0-*

Affected platform version
  • .NET SDK 10.0.402 with Microsoft.iOS.Sdk 27.1.10018
  • .NET SDK 11.0.100-rc.2.26504.105 with Microsoft.iOS.Sdk 27.0.12212-net11-rc.2
Description

After changing a dependency's version and rebuilding without a clean, the resulting .app should match what a clean build produces. Instead, two separate timestamp-based up-to-date checks treat NuGet assemblies as unchanged, because package files keep the timestamp they were built with. Depending on the direction of the package version change, runtime, and link mode, the app either aborts at launch or silently runs the old assembly.

Project Downgrade (13.0.4 → 13.0.1) Upgrade (13.0.1 → 13.0.4)
net10.0-ios with the default _LinkMode=SdkOnly aborts at launch with Failed to load AOT module 'Newtonsoft.Json'; the bundle still contains the 13.0.4 DLL works (I don't know why; the linked DLL has the same old timestamp)
net10.0-ios with MtouchLink=None aborts at launch with Failed to load AOT module 'aot-instances'; the bundle still contains the 13.0.4 DLL aborts at launch with Failed to load AOT module 'Newtonsoft.Json'
net11.0-ios RC2 build succeeds, but the app bundle still contains 13.0.4 instead of 13.0.1, and anything that relies on that assembly gets the incorrect version works
Cause A: bundle files are copied only if the source is newer

The bundle is populated by _CopyResolvedFilesToPublishPreserveNewest (Microsoft.NET.Publish.targets), which uses Inputs/Outputs and copies only when the source is newer than the destination. Xamarin.Shared.Sdk.targets marks the bundle's assemblies, native references, aot-instances.dll, .aotdata files and the executable as CopyToPublishDirectory=PreserveNewest. After a downgrade, the older package DLL is older than the one already in the bundle, so it is skipped. This is the net11 result above.

Cause B: the AOT up-to-date check is timestamp-only, and assumes newer outputs are more up-to-date

From AOTCompile.IsUpToDate in msbuild/Xamarin.MacDev.Tasks/Tasks/AOTCompile.cs:

bool IsUpToDate (FileInfo input, FileInfo output)
{
    if (!output.Exists) return false;
    return input.LastWriteTimeUtc <= output.LastWriteTimeUtc;
}

In the failed MtouchLink=None upgrade, linked/Newtonsoft.Json.dll (13.0.4, the new input) has mtime 2025-09-16 02:04, the same as the file in the NuGet cache, while nativelibraries/aot-output/arm64/Newtonsoft.Json.dll.o has mtime 2026-10-26 20:59, the time of the prior build. The input is older than the output, so it is treated as up to date and not recompiled. The .o appears to be left over from the previous (13.0.1) build.

Steps to Reproduce
Create a sample project:
  1. Create a global.json to pin the version of .NET that you want to test.

  2. dotnet new ios -n StaleSample

  3. In StaleSample.csproj, add:

    <PropertyGroup>
      <NewtonsoftVersion Condition="'$(NewtonsoftVersion)' == ''">13.0.4</NewtonsoftVersion>
    </PropertyGroup>
    
    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftVersion)" />
    </ItemGroup>
    
  4. In AppDelegate.cs, add using System.Reflection; at the top, and in AppDelegate.FinishedLaunching, before return true, add:

    var version = typeof(Newtonsoft.Json.JsonConvert)
        .Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
        .InformationalVersion ?? "unknown";
    
    Console.WriteLine($"StaleSample: Newtonsoft.Json {version}");
    
For net10.0-ios:

Create the above project using net10.0-ios, then:

To reproduce the .NET 10 downgrade crash with the default linker configuration:

  1. dotnet clean
  2. dotnet build -p:NewtonsoftVersion=13.0.4, then install and launch. The logs show 13.0.4.
  3. dotnet build -p:NewtonsoftVersion=13.0.1, then install and launch. The app crashes.

To reproduce the .NET 10 downgrade crash with the disabled linker configuration:

  1. dotnet clean
  2. dotnet build -p:NewtonsoftVersion=13.0.4 -p:MtouchLink=None, then install and launch. The logs show 13.0.4.
  3. dotnet build -p:NewtonsoftVersion=13.0.1 -p:MtouchLink=None, then install and launch. The app crashes.

To reproduce the .NET 10 upgrade crash with the disabled linker configuration:

  1. dotnet clean
  2. dotnet build -p:NewtonsoftVersion=13.0.1 -p:MtouchLink=None, then install and launch. The logs show 13.0.1.
  3. dotnet build -p:NewtonsoftVersion=13.0.4 -p:MtouchLink=None, then install and launch. The app crashes.
For net11.0-ios:

Create the above project using net11.0-ios, then:

  1. dotnet clean
  2. dotnet build -p:NewtonsoftVersion=13.0.4, then install and launch. The logs show 13.0.4.
  3. dotnet build -p:NewtonsoftVersion=13.0.1, then install and launch. The logs still show 13.0.4 when they should show 13.0.1.
Did you find any workaround?

Yes. Delete bin/<config>/<tfm>/<rid>/<App>.app, obj/<config>/<tfm>/<rid>/nativelibraries, and obj/.../aot-instances.dll before rebuilding.

Build logs

No response

Lingua principale
C#
Stelle
2.9k
Fork
578
Merge medio
2g 12h
PR unite (30g)
189

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di dotnet/macios

Tutte le issue di dotnet/macios

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.