Repository navigation
AOT: guard akka.extensions and custom akka.actor.provider reflection behind Akka.DynamicTypeLoading - #8670
Merged
Aaronontheweb merged 4 commits intoSep 30, 2026
Conversation
…hind the DynamicTypeLoading switch ActorSystemImpl.LoadExtensions and the custom-provider validation in Settings / ActorSystemImpl.ConfigureProvider were the last two IL2xxx sites the AOT canary's unrooted publish hit (akkadotnet#7246). Both now check AkkaFeatures.IsDynamicTypeLoadingSupported before falling back to Type.GetType, throwing ConfigurationException(AkkaFeatures.NotBuiltIn(...)) when the switch is off, matching the pattern already used for the scheduler, log formatter and stdout logger. With the switch on, behavior is unchanged. With it off: an akka.extensions entry that isn't a first-party extension (akkadotnet#8648) throws instead of being logged and skipped, and a custom akka.actor.provider throws instead of going through reflection. Removes the corresponding entries from the AOT warning baseline; the unrooted canary publish is now warning-free except for TypeCache (tracked separately). Adds AkkaFeaturesSpec coverage for both switch states and a BREAKING_CHANGES_V1.6.md row.
5 tasks done
…t-party extensions as not-built-in Two review fixes on top of the extensions/provider switch-off guard: 1. ProviderSelection.GetProvider matched akka.actor.provider by exact string, so a spelling variant of a built-in provider - no space after the comma (e.g. "Akka.Cluster.ClusterActorRefProvider,Akka.Cluster"), or a versioned assembly-qualified name - fell through to Custom. With the switch off that meant a working built-in provider threw NotBuiltIn. GetProvider now normalizes through TypeExtensions.TrySplitTypeName (the akkadotnet#8613 rule: strip the assembly identity, split at the comma, compare the assembly case-insensitively) against a small BuiltInProviders table, so every accepted spelling maps to the same ProviderSelection instead. This also fixes Settings.HasCluster being wrongly false for such a spelling, independent of the switch. 2. LoadExtensions treated a first-party extensions-table name whose assembly isn't deployed (TryCreateFirstPartyExtension returns null either way) the same as a name that isn't in the table at all, so with the switch off it threw NotBuiltIn for a name akkadotnet#8648 already promised to log-and-skip. A new IsFirstPartyExtensionName reports a table hit regardless of whether the assembly loads, so LoadExtensions can log-and-skip the absent-module case before reaching the switch-off guard - matching the switch-on behavior, which already fell through to the same log message. Tests added to AkkaFeaturesSpec (provider spelling classification and its end-to-end consequence in both switch states, plus the absent-assembly extension case) and ExtensionsSetupSpec (IsFirstPartyExtensionName). Updates the BREAKING_CHANGES_V1.6.md row to name both cases.
# Conflicts: # BREAKING_CHANGES_V1.6.md
Aaronontheweb
commented
Sep 30, 2026
| continue; | ||
| } | ||
|
|
||
| if (!AkkaFeatures.IsDynamicTypeLoadingSupported) |
This was referenced Sep 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
Closes the last two
IL2xxxsites the AOT canary's unrooted publish hit (#7246); seesrc/aot/Akka.AOT.App/README.mdfor the canary itself.ActorSystemImpl.LoadExtensions(): anakka.extensionsentry that isn't one of Akka'sfirst-party extensions (AOT: ExtensionsSetup and a first-party akka.extensions table #8648) now checks
AkkaFeatures.IsDynamicTypeLoadingSupportedbefore falling through to
Type.GetType. Off, it throwsConfigurationException(AkkaFeatures.NotBuiltIn(...))naming the setting, the value andthe switch, pointing at
ExtensionsSetup. On, unchanged. TheType.GetTypecall itselfmoves into a new
[RequiresUnreferencedCode]helper,ResolveExtensionType.akka.actor.provider: bothSettings' validation andActorSystemImpl.ConfigureProvider's fallback arm needed the same guard -Settingsrunsfirst and would already reject a bad value, but the trim analyzer has no way to know that,
so
ConfigureProvider'sIL2072needed its own fix.ConfigureProvider's switch expressionbecame an
if/else ifchain (matchingConfigureScheduler/the logger settings) so theAkkaFeatures.IsDynamicTypeLoadingSupportedguard is visible to the analyzer, and thefallback now calls a new
CreateCustomProvider([RequiresUnreferencedCode]) instead ofthe existing
CreateProvider, whosetypeNameparameter carries[DynamicallyAccessedMembers(PublicConstructors)]-Settings.ProviderClasshas no suchannotation, so passing it through that parameter warned
IL2072regardless of the guard.Deletes the three now-fixed lines from
aot-warnings.baseline.txt's UNROOTED section(extensions,
ConfigureProvider,Settingsctor).TypeCache/manifest resolution is theremaining UNROOTED entry, tracked in a follow-up PR - this PR and that one both touch
aot-warnings.baseline.txt, so expect a small conflict between them depending on mergeorder.
Review fixes (61d34ab)
Two issues found in review, both fixed on this branch:
ProviderSelection.GetProvidermatched by exact string. A spelling variant of abuilt-in provider - no space after the comma (e.g.
"Akka.Cluster.ClusterActorRefProvider,Akka.Cluster"), or a versionedassembly-qualified name - fell through to
Custom. With the switch off that meant aworking built-in provider wrongly threw
NotBuiltIn.GetProvidernow normalizesthrough
TypeExtensions.TrySplitTypeName(the AOT M1-G: one matching rule for every built-in type name #8613 rule: strip the assembly identity,split at the comma, compare the assembly case-insensitively) against a small
BuiltInProviderstable, so every accepted spelling of the three built-ins maps to thesame
ProviderSelection. This also fixesSettings.HasClusterbeing wronglyfalseforsuch a spelling - independent of the switch, a pre-existing bug. Added a classification
theory (
ProviderSelection.GetProviderdirectly) plus an end-to-end theory over bothswitch states proving the spelling now fails for the provider's own reason
(
"Akka.Cluster is not referenced by this application", since Akka.Tests doesn'treference Akka.Cluster/Akka.Remote) rather than
NotBuiltIn, and a Local-providerspelling-variant test that boots a real
ActorSystemend to end (Local ships inAkka.dll, so it's the one variant this project can actually construct).
TryCreateFirstPartyExtensionreturnsnullboth when a name isn't in the first-partytable and when it is but the assembly won't load (e.g.
Akka.DistributedDatalisted butnot deployed) - AOT: ExtensionsSetup and a first-party akka.extensions table #8648 promised the latter is logged and skipped, same as reflection. With
the switch off this PR's new guard didn't distinguish the two and threw
NotBuiltInforboth. Added
ActorSystemImpl.IsFirstPartyExtensionName, which reports a table hitregardless of whether the assembly loads;
LoadExtensionsnow checks it before theswitch-off guard, so an absent-module name logs-and-skips in either switch state, and only
a name that isn't in the table at all is rejected as not built in. Covered in
ExtensionsSetupSpec(the new method directly) andAkkaFeaturesSpec(an end-to-endActorSystem.Createover both switch states with the same absentDistributedDataProvidername the existing table-level test already uses).
Verification
dotnet publish src/aot/Akka.AOT.App -r linux-x64 -c Release -p:TrimmerSingleWarn=false(unrooted): 4 warnings on
dev-> 1 on this branch (TypeCacheonly, unchanged by thereview fixes). Canary still prints
[canary] OK, exit 0.-p:RootAkka=true:dotnet run scripts/CheckAotWarnings.csreports 9in-scope warnings against 9 baseline entries, no new, none stale.
dotnet test src/core/Akka.Tests -c Release --framework net10.0 --filter FullyQualifiedName~Akka.Tests.Actor|FullyQualifiedName~Akka.Tests.Util:729 passed, 12 skipped (pre-existing), 0 failed (was 717 before the review-fix commit;
the +12 are the new spelling/absent-assembly cases).
dotnet test src/core/Akka.Tests -c Release --framework net10.0 --filter FullyQualifiedName~AkkaFeaturesSpec|FullyQualifiedName~ExtensionsSetupSpec:56 passed, 0 failed.
dotnet test src/core/Akka.API.Tests -c Release --framework net10.0 --filter FullyQualifiedName~ApproveCore:passes with no diff - every new member is
internal/private, so there is no public APIchange.
Breaking changes
Akka(core / actor system bootstrap)ActorSystemImpl.LoadExtensionsand the customakka.actor.providervalidation inSettingsandActorSystemImpl.ConfigureProvidernow put theirType.GetTypefallback behind theAkka.DynamicTypeLoadingswitch, closing the last twoIL2xxxwarnings the AOT canary's unrooted publish hit (#7246). With the switch on, both resolve exactly as before. With it off: anakka.extensionsentry that is not one of Akka's first-party extensions (#8648) now throwsConfigurationExceptionfromAkkaFeatures.NotBuiltInnaming the setting, the value and the switch, in place of logging"is not an 'ExtensionId'"and skipping it; a custom (non-built-in)akka.actor.providerlikewise throws fromAkkaFeatures.NotBuiltIninstead of attemptingType.GetTypeat all -- on the JIT that used to succeed for any provider that actually resolved, since nothing enforced the switch at this site yet; only a trimmed/AOT publish caught it, as anIL2057/IL2072build-time warning rather than a runtime failure. Two review fixes are folded in: (1)ProviderSelection.GetProvidernow normalizesakka.actor.providerthe same way theBuiltIn*tables do (#8613) before falling back toCustom, so a spelling variant of a built-in provider -- no space after the comma, or a versioned assembly-qualified name -- is recognized as the built-in instead of being misclassified as custom (which, with the switch off, would have wrongly thrownNotBuiltInfor a name that is in fact built in; this also fixesSettings.HasClusterbeing wronglyfalsefor such a spelling, independent of the switch); (2) a first-partyakka.extensionsname (#8648) whose assembly is not deployed now logs and skips exactly as it does with the switch on, instead of throwingNotBuiltIn-- only a name that is not in the first-party table at all is rejected that way.ExtensionsSetupinstead ofakka.extensions, and keepakka.actor.provideratlocal,remoteorcluster(or the assembly-qualified name of the built-in provider type).(The shared
BREAKING_CHANGES_V1.6.mdledger itself is not touched by this PR -- it is updated in a separate batch PR.)Checklist
dotnet build -c Release -warnaserrorforAkkaandAkka.TestsAkkaFeaturesSpec,ExtensionsSetupSpec, plus the existingAkka.Tests.Actor/Akka.Tests.Utilsuites for regressions)Akka.API.TestsApproveCore: no diff (no public API touched)CheckAotWarningsreports no new warnings