Apple platform
iOS
Framework version
net10.0-*
Affected platform version
VS 2026 & .NET 10
Description
Summary
After migrating from .NET 9 (VS2022) to .NET 10 (VS2026), my iOS App Extension used by my main .NET MAUI project is no longer produced on the Mac build host when building via Pair-to-Mac.
This appears to be consistent with other reports since Dec 2025 regarding VS 2026:
Failure
After moving to .NET 10 and VS2026, the main MAUI application now fails with:
Xamarin.Shared.targets(2750,3): error :
The source '../../AppexProj/fa65c132.../bin/Debug/net10.0-ios/ios-arm64/AppexProj.appex' does not exist.
Environment
- Visual Studio 2026
- .NET 10 (
net10.0-ios)
- Pair-to-Mac build
- macOS 15.6
- Apple Silicon Mac
- Notification Service Extension project referenced from MAUI app using:
<ItemGroup Condition="$(TargetFramework.Contains('-ios'))">
<ProjectReference Include="..\AppexProj\AppexProj.csproj">
<IsAppExtension>true</IsAppExtension>
<IsWatchApp>false</IsWatchApp>
</ProjectReference>
</ItemGroup>
This configuration worked previously under .NET 9 / VS2022 with no changes except upgrade to .NET 10 / VS2026.
Observations:
Running in the Appex csproj:
<Target Name="DumpAppexProjBuildStage" BeforeTargets="_CodesignAppBundle">
<Message Text="[AppexProj] Before _CodesignAppBundle TargetFile=$(ProjectDir)$(IntermediateOutputPath)$(TargetFileName)" Importance="High" />
</Target>
<Target Name="DumpAfterCodesign" AfterTargets="_CodesignAppBundle">
<Message Text="[AppexProj] AFTER _CodesignAppBundle" Importance="High" />
<Message Text="[AppexProj] AppBundleDir=$(AppBundleDir)" Importance="High" />
<Message Text="[AppexProj] Exists=$([System.IO.Directory]::Exists('$(AppBundleDir)'))" Importance="High" />
<Message Text="[AppexProj] AssemblyName=$(AssemblyName)" Importance="High" />
</Target>
<Target Name="DumpSdkProperties" AfterTargets="_CodesignAppBundle">
<Message Text="[AppexProj] IsAppExtension=$(IsAppExtension)" Importance="High" />
<Message Text="[AppexProj] TargetFramework=$(TargetFramework)" Importance="High" />
<Message Text="[AppexProj] RuntimeIdentifier=$(RuntimeIdentifier)" Importance="High" />
<Message Text="[AppexProj] OutputType=$(OutputType)" Importance="High" />
</Target>
<Target Name="DumpExtensionTargets" BeforeTargets="_CodesignAppBundle">
<Message Text="[AppexProj] IntermediateOutputPath=$(IntermediateOutputPath)" Importance="High" />
<Message Text="[AppexProj] OutputPath=$(OutputPath)" Importance="High" />
</Target>
<Target Name="DebugGetBundleTargetPath" BeforeTargets="GetBundleTargetPath">
<Message Text="[AppexProj] GetBundleTargetPath called" Importance="High" />
</Target>
<Target Name="AppexProjAfterBuild"
AfterTargets="Build">
<Message Text="[AppexProj] BUILD EXECUTED" Importance="High" />
</Target>
<Target Name="AppexProjAfterBundlePath"
AfterTargets="GetBundleTargetPath">
<Message Text="[AppexProj] GetBundleTargetPath finished" Importance="High" />
</Target>
<Target Name="DebugBundlePath" AfterTargets="GetBundleTargetPath">
<Message Text="[AppexProj] AppBundleDir=$(AppBundleDir)" Importance="High" />
<Message Text="[AppexProj] AppBundlePath=$(AppBundlePath)" Importance="High" />
<Message Text="[AppexProj] OutputPath=$(OutputPath)" Importance="High" />
</Target>
Produces:
1> [AppexProj] Before _CodesignAppBundle TargetFile=C:\....\obj\Debug\net10.0-ios\ios-arm64\AppexProj.dll
1> [AppexProj] IntermediateOutputPath=obj\Debug\net10.0-ios\ios-arm64\
1> [AppexProj] OutputPath=bin\Debug\net10.0-ios\ios-arm64\
1> [AppexProj] AFTER _CodesignAppBundle
1> [AppexProj] AppBundleDir=bin\Debug\net10.0-ios\ios-arm64\AppexProj.appex
1> [AppexProj] Exists=False
1> [AppexProj] AssemblyName=AppexProj
1> [AppexProj] IsAppExtension=True
1> [AppexProj] TargetFramework=net10.0-ios
1> [AppexProj] RuntimeIdentifier=ios-arm64
1> [AppexProj] OutputType=Library
1> [AppexProj] BUILD EXECUTED
2> [AppexProj] GetBundleTargetPath called
2> [AppexProj] GetBundleTargetPath finished
2> [AppexProj] AppBundleDir=bin\Debug\net10.0-ios\ios-arm64\device-builds\iphone14.2-26.5/AppexProj.appex
2> [AppexProj] AppBundlePath=
2> [AppexProj] OutputPath=bin\Debug\net10.0-ios\ios-arm64\
Searching the Pair-to-Mac cache on the Mac shows no AppexProj artifacts at all:
find ~/Library/Caches/maui/PairToMac -iname "*AppexProj*"
returns no results.
No:
- AppexProj.csproj
- AppexProj.dll
- AppexProj.appex
are present anywhere in the Pair-to-Mac build cache.
However, the main application project is present and built successfully in the Pair-to-Mac cache.
Conclusions
We can then conclude:
- The extension project is correctly recognized as an app extension.
- The extension assembly (AppexProj.dll) is successfully produced during the extension project build on Windows - I can open the AppexProj.dll on Windows in ilspy, showing it has all the expected code in it (it is not malformed).
- App extension hooks are firing, indicating the pipeline does recognize this is an app extension.
- No AppexProj artifacts are present anywhere in the Pair-to-Mac cache on the Mac.
- No appex dll or .appex file ends up on the mac at all - searching for the appex dll or project name in the mac anywhere no longer returns anything.
The extension project is not only discovered but actually built:
[IOSAppex] BUILD EXECUTED
and GetBundleTargetPath is subsequently invoked:
[IOSAppex] GetBundleTargetPath called
[IOSAppex] GetBundleTargetPath finished
This suggests the extension project participates in the build graph and is queried for its bundle path, but the expected remote output is not present when _CopyAppExtensionsToBundle executes.
GetBundleTargetPath returns: bin\Debug\net10.0-ios\ios-arm64\device-builds\iphone14.2-26.5/AppexProj.appex
while the final error is looking for: ../../AppexProj/fa65c132.../bin/Debug/net10.0-ios/ios-arm64/AppexProj.appex
Error Trace
The precise error line referenced shows:
C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net10.0_26.2\26.2.10233\tools\msbuild\Xamarin.Shared.targets
<Target Name="_CopyAppExtensionsToBundle"
DependsOnTargets="_ExtendAppExtensionReferences;_ResolveAppExtensionReferences;_PlaceAppExtensions"
Inputs="@(_ResolvedAppExtensionReferences)"
Outputs="$(_AppExtensionRoot)%(_ResolvedAppExtensionReferences.ContainerName)\%(_ResolvedAppExtensionReferences.FileName)%(_ResolvedAppExtensionReferences.Extension)"
>
<MakeDir
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
Directories="$(_AppExtensionRoot)%(_ResolvedAppExtensionReferences.ContainerName)"
/>
<Ditto
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
DittoPath="$(DittoPath)"
Source="@(_ResolvedAppExtensionReferences)"
Destination="$(_AppExtensionRoot)%(_ResolvedAppExtensionReferences.ContainerName)\%(_ResolvedAppExtensionReferences.FileName)%(_ResolvedAppExtensionReferences.Extension)"
TouchDestinationFiles="true"
/>
<!-- Delete any code signatures and dSYM dirs since they are now invalid -->
<RemoveDir
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
Directories="$(_AppExtensionRoot)%(_ResolvedAppExtensionReferences.ContainerName)\%(_ResolvedAppExtensionReferences.FileName)%(_ResolvedAppExtensionReferences.Extension)\_CodeSignature;
$(_AppBundlePath)..\%(_ResolvedAppExtensionReferences.FileName)%(_ResolvedAppExtensionReferences.Extension).dSYM"
/>
</Target>
where line 2750 is: <Ditto
Thus the failure is occurring at the point where the Xamarin flow expects the .appex file to exist in the mac at the hashed path but it does not.
That is:
- The extension project is discovered.
- The extension project is evaluated.
GetBundleTargetPath is invoked.
- The extension reference is resolved.
Then the failure occurs because the SDK attempts to copy:
../../AppexProj/fa65c132e9419536e1f9139246d307544dd5b56dd714a71467583377dc46faac/bin/Debug/net10.0-ios/ios-arm64/AppexProj.appex
which does not exist.
Expected Behavior
The app extension should be built/synchronized to the Mac and produce the expected .appex output before _CopyAppExtensionsToBundle attempts to copy it. This was previously working in .NET 9 and VS2022.
Actual Behavior
The app extension reference is resolved, but no corresponding extension output exists on the Mac build host. _CopyAppExtensionsToBundle then fails when attempting to copy the expected .appex.
Working Hypothesis
There appears to be a regression either in Pair-to-Mac synchronization or in the app-extension build pipeline. The extension project is recognized, built, and queried via GetBundleTargetPath, but the expected .appex output is not present at the remote location when _CopyAppExtensionsToBundle executes.
Thanks for any help.
@rolfbjarne
Steps to Reproduce
Please see above explanation.
Did you find any workaround?
I could not find a workaround despite my best efforts. I tried the suggestion here: #25461 which suggested:
<!-- Add this to the main executable project: -->
<PropertyGroup>
<_BuildReferencedExtensionProjects>true</_BuildReferencedExtensionProjects>
</PropertyGroup>
<!-- Add this to all the extension projects (if more than one):-->
<PropertyGroup>
<!-- replace with the IP address of the remote mac -->
<ServerAddress>MacIP</ServerAddress>
<!-- replace with the username of the remote mac user -->
<ServerUser>MacUser</ServerUser>
<!-- if building for simulator, set RuntimeIdentifier=iossimulator-arm64 -->
<!-- if building for device, set RuntimeIdentifier=ios-arm64 -->
<!-- this has to be switched manually whenever changing the target in the IDE's UI, and the build errors you'll get if you forget will unfortunately not be very useful -->
<RuntimeIdentifier>iossimulator-arm64</RuntimeIdentifier>
</PropertyGroup>
This seemed to change the failure point. Instead then the build broke on:
3> [AppexProj][MAINPROJ] Filename=AppexProj
3> [AppexProj][MAINPROJ] Extension=.dll
3> Finished external tool execution #54 in 00:00:00.0400265 and with exit code 1.
3> error: cannot parse the debug map for '/Users/../Library/Caches/maui/PairToMac/Builds/MainProj/b760af4660bd5c72f7a189de8ff7ee746b3396ba0a4215dffbb20df0806d947c/bin/Debug/net10.0-ios/ios-arm64/device-builds/iphone14.2-26.5/MainProj.app/PlugIns/AppexProj.appex/': No such file or directory
3>C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net10.0_26.2\26.2.10233\tools\msbuild\Xamarin.Shared.targets(3077,3): error : dsymutil exited with code 1:
3>C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net10.0_26.2\26.2.10233\tools\msbuild\Xamarin.Shared.targets(3077,3): error : error: cannot parse the debug map for '/Users/../Library/Caches/maui/PairToMac/Builds/MainProj/b760af4660bd5c72f7a189de8ff7ee746b3396ba0a4215dffbb20df0806d947c/bin/Debug/net10.0-ios/ios-arm64/device-builds/iphone14.2-26.5/MainProj.app/PlugIns/AppexProj.appex/': No such file or directory
So it seems we still cannot make it work using this approach.
Build logs
I am unfortunately unable to share binlogs due to proprietary code and project information contained within them.
I have instead included the relevant diagnostic output and target traces that led to the detailed observations and conclusions above. Hopefully that will help narrow down the cause.
Apple platform
iOS
Framework version
net10.0-*
Affected platform version
VS 2026 & .NET 10
Description
Summary
After migrating from .NET 9 (VS2022) to .NET 10 (VS2026), my iOS App Extension used by my main .NET MAUI project is no longer produced on the Mac build host when building via Pair-to-Mac.
This appears to be consistent with other reports since Dec 2025 regarding VS 2026:
Failure
After moving to .NET 10 and VS2026, the main MAUI application now fails with:
Environment
net10.0-ios)This configuration worked previously under .NET 9 / VS2022 with no changes except upgrade to .NET 10 / VS2026.
Observations:
Running in the Appex csproj:
Produces:
Searching the Pair-to-Mac cache on the Mac shows no AppexProj artifacts at all:
returns no results.
No:
are present anywhere in the Pair-to-Mac build cache.
However, the main application project is present and built successfully in the Pair-to-Mac cache.
Conclusions
We can then conclude:
The extension project is not only discovered but actually built:
[IOSAppex] BUILD EXECUTEDand GetBundleTargetPath is subsequently invoked:
This suggests the extension project participates in the build graph and is queried for its bundle path, but the expected remote output is not present when
_CopyAppExtensionsToBundleexecutes.GetBundleTargetPath returns:
bin\Debug\net10.0-ios\ios-arm64\device-builds\iphone14.2-26.5/AppexProj.appexwhile the final error is looking for:
../../AppexProj/fa65c132.../bin/Debug/net10.0-ios/ios-arm64/AppexProj.appexError Trace
The precise error line referenced shows:
C:\Program Files\dotnet\packs\Microsoft.iOS.Sdk.net10.0_26.2\26.2.10233\tools\msbuild\Xamarin.Shared.targetswhere line 2750 is:
<DittoThus the failure is occurring at the point where the Xamarin flow expects the .appex file to exist in the mac at the hashed path but it does not.
That is:
GetBundleTargetPathis invoked.Then the failure occurs because the SDK attempts to copy:
which does not exist.
Expected Behavior
The app extension should be built/synchronized to the Mac and produce the expected
.appexoutput before_CopyAppExtensionsToBundleattempts to copy it. This was previously working in .NET 9 and VS2022.Actual Behavior
The app extension reference is resolved, but no corresponding extension output exists on the Mac build host.
_CopyAppExtensionsToBundlethen fails when attempting to copy the expected.appex.Working Hypothesis
There appears to be a regression either in Pair-to-Mac synchronization or in the app-extension build pipeline. The extension project is recognized, built, and queried via GetBundleTargetPath, but the expected .appex output is not present at the remote location when _CopyAppExtensionsToBundle executes.
Thanks for any help.
@rolfbjarne
Steps to Reproduce
Please see above explanation.
Did you find any workaround?
I could not find a workaround despite my best efforts. I tried the suggestion here: #25461 which suggested:
This seemed to change the failure point. Instead then the build broke on:
So it seems we still cannot make it work using this approach.
Build logs
I am unfortunately unable to share binlogs due to proprietary code and project information contained within them.
I have instead included the relevant diagnostic output and target traces that led to the detailed observations and conclusions above. Hopefully that will help narrow down the cause.