App aborts with "Failed to load AOT module" after a NuGet version change without a clean build
I maintainer di solito rispondono entro 1 giorno
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
- Ambito
- build-system, mobile-dev
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
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:
-
Create a
global.jsonto pin the version of .NET that you want to test. -
dotnet new ios -n StaleSample -
In
StaleSample.csproj, add:<PropertyGroup> <NewtonsoftVersion Condition="'$(NewtonsoftVersion)' == ''">13.0.4</NewtonsoftVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftVersion)" /> </ItemGroup> -
In
AppDelegate.cs, addusing System.Reflection;at the top, and inAppDelegate.FinishedLaunching, beforereturn 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:
dotnet cleandotnet build -p:NewtonsoftVersion=13.0.4, then install and launch. The logs show 13.0.4.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:
dotnet cleandotnet build -p:NewtonsoftVersion=13.0.4 -p:MtouchLink=None, then install and launch. The logs show 13.0.4.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:
dotnet cleandotnet build -p:NewtonsoftVersion=13.0.1 -p:MtouchLink=None, then install and launch. The logs show 13.0.1.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:
dotnet cleandotnet build -p:NewtonsoftVersion=13.0.4, then install and launch. The logs show 13.0.4.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
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di dotnet/macios
-
NSString(string) keeps an extra native reference, so every NSString created from a managed string leaksForse già presa @rolfbjarne l’ha presa 3 giorni fa. Apertabackport-to-net10.0 backport-to-net11.0 bug regression
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
dotnet/macios#27042 · 1 commento · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
[Network] Align NWIPVersion enum values with native nw_ip_version_tForse già presa @rolfbjarne l’ha presa 3 giorni fa. Apertaapi-bindings copilot
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
dotnet/macios#26802 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
[Network] Bind the waiting state for NWBrowserStateForse già presa @rolfbjarne l’ha presa 16 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
ci-failure ci-postmortem tests
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
I maintainer di solito rispondono entro 1 giorno
-
Specifying both RuntimeIdentifier + RuntimeIdentifiers can confuse the build.Forse già presa @rolfbjarne l’ha presa 7 giorni fa. Apertabug msbuild regression
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
dotnet/macios#25463 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di dotnet/macios
Issue simili
-
bug effort:S P3
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
nightscout/nocturne#3093 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
I maintainer di solito rispondono entro 3 giorni
-
Add 'upm' tag on githubAperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100