You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Xcode 26.4+ writes Swift Package Manager traits (SE-0450) into project.pbxproj as traits = ( ... ); entries on XCRemoteSwiftPackageReference and XCLocalSwiftPackageReference. Stock XcodeProj 9.11.0 has no traits field on these types, so any tool that loads such a project and calls XcodeProj.write() silently discards the user's trait selection. On next open, Xcode sees no traits key and falls back to default traits re-enabling features the user opted out of, or pulling back frameworks they excluded (e.g. a NoUIFramework selection that kept UIKit/AppKit out would quietly come back on).
git clone https://github.com/chigichan24/XcodeProj-MinimalProject
cd XcodeProj-MinimalProject
./compare.sh
The Stock/ side (pinned to XcodeProj exact 9.11.0) prints:
fixture has 5 trait-related lines ...
after load -> write: 0 trait-related lines
Result: traits preserved in output pbxproj = NO
The Branch/ side (patch applied) preserves them and passes every round-trip check.
Impact
Downstream generators built on XcodeProj (notably feat: Package traits yonaskolb/XcodeGen#1585) cannot emit traits while this field is absent from the public model. Users of such generators today are either stuck without traits or hand-committing the generated .xcodeproj to preserve them
(as the Sentry team does).
Proposed direction
Add traits: [String]? to XCRemoteSwiftPackageReference and XCLocalSwiftPackageReference. Keep nil vs [] distinct (SE-0450 treats traits: [] as "disable default traits"). No public-API change for projects not using traits.
Summary
Xcode 26.4+ writes Swift Package Manager traits (SE-0450) into
project.pbxprojastraits = ( ... );entries onXCRemoteSwiftPackageReferenceandXCLocalSwiftPackageReference. StockXcodeProj9.11.0 has notraitsfield on these types, so any tool that loads such a project and callsXcodeProj.write()silently discards the user's trait selection. On next open, Xcode sees notraitskey and falls back to default traits re-enabling features the user opted out of, or pulling back frameworks they excluded (e.g. aNoUIFrameworkselection that kept UIKit/AppKit out would quietly come back on).pbxproj format in the wild
Real-world examples:
getsentry/sentry-cocoamacOS-CLI-Xcode sample:XCLocalSwiftPackageReferencewithtraits = ( NoUIFramework, );ml-explore/mlx-swift-examples:XCRemoteSwiftPackageReferencewithtraits = ( );(empty = explicit default-trait opt-out, semantically distinct from an absent key)Confirmed introduced in Xcode 26.4 (stable, currently 26.4.1); not emitted by 26.3 or earlier.
Reproducer
https://github.com/chigichan24/XcodeProj-MinimalProject
git clone https://github.com/chigichan24/XcodeProj-MinimalProject cd XcodeProj-MinimalProject ./compare.shThe
Stock/side (pinned to XcodeProj exact 9.11.0) prints:The
Branch/side (patch applied) preserves them and passes every round-trip check.Impact
.xcodeprojto preserve them(as the Sentry team does).
Proposed direction
Add
traits: [String]?toXCRemoteSwiftPackageReferenceandXCLocalSwiftPackageReference. Keepnilvs[]distinct (SE-0450 treatstraits: []as "disable default traits"). No public-API change for projects not using traits.