Removing a target referenced by PBXFileSystemSynchronizedBuildFileExceptionSet crashes serialization
Nobody has claimed this yet.
- Dominant language
- Swift
- Stars
- 2.2k
- Forks
- 355
- Avg merge
- 5h 48m
- Merged PRs (30d)
- 13
Description
Summary
Calling removeFromProject() on a PBXNativeTarget does not cascade to PBXFileSystemSynchronizedBuildFileExceptionSet objects that reference that target. The orphaned exception sets retain a nil target reference, which crashes during serialization when generating the plist annotation (target.name on nil).
Minimal reproduction
Setup (Xcode 16+):
- Create a project with two app targets: AppA and AppB
- Create a folder
SharedSrc/containingShared.swiftandInfo.plist - In Xcode, drag
SharedSrc/into the project as a synchronized folder reference, with both targets checked - Select
Info.plistin the navigator, open the File Inspector, and uncheck AppB from Target Membership
This creates a PBXFileSystemSynchronizedBuildFileExceptionSet with target = AppB inside the SharedSrc synchronized root group — meaning "exclude Info.plist from AppB's build."
Reproduction (Ruby xcodeproj gem v1.27.0):
require "xcodeproj"
proj = Xcodeproj::Project.open("Repro.xcodeproj")
# Removing AppA works fine (not referenced by any exception set)
proj.targets.find { |t| t.name == "AppA" }.remove_from_project
proj.save # => OK
# Removing AppB crashes (referenced by the exception set)
proj.targets.find { |t| t.name == "AppB" }.remove_from_project
proj.save # => CRASH
Crash:
PBXFileSystemSynchronizedBuildFileExceptionSet#display_name: undefined method 'name' for nil (NoMethodError)
"Exceptions for \"#{GroupableHelper.parent(self).display_name}\" in \"#{target.name}\" target"
What happens
removeFromProject()on the target removes thePBXNativeTargetobject, its build configuration list, and its build phases- It does not remove
PBXFileSystemSynchronizedBuildFileExceptionSetobjects whosetargetproperty pointed to the removed target - On save, the serializer calls
display_nameon each exception set, which accessestarget.name— now nil — and crashes
What should happen
removeFromProject() on a PBXNativeTarget should also remove any PBXFileSystemSynchronizedBuildFileExceptionSet whose target references the removed target. Xcode's UI does this cleanup when deleting a target — the programmatic API should match.
Additional incomplete cascading
Beyond exception sets, removeFromProject() also leaves behind:
PBXFileReferencefor the target's product (.app,.xctest)- The product reference in the Products group
PBXGroupentries for the target's source directory
These don't crash serialization but leave orphaned entries in the project file.
Workaround
Clean up orphaned exception sets manually before saving:
proj.objects.select { |o|
o.isa == "PBXFileSystemSynchronizedBuildFileExceptionSet" &&
o.respond_to?(:target) && o.target.nil?
}.each { |o| o.remove_from_project }
Environment
- Ruby xcodeproj gem 1.27.0
- Project created with Xcode 26 beta (uses synchronized folders /
PBXFileSystemSynchronizedRootGroup) - Also reproduced via xcodeproj-mcp-server v1.5.0, which uses the Swift tuist/XcodeProj library — same crash (exit code 133 / SIGTRAP, the Swift equivalent of nil access)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at PBXNativeTarget#remove_from_project and PBXFileSystemSynchronizedBuildFileExceptionSet#display_name, then reproduce the AppA/AppB case from the issue with the Ruby xcodeproj gem. Trace how target references are removed and how serialization reaches the exception set. Done means removing a referenced target cleans up its exception sets and saving no longer crashes; consider the listed orphaned entries if they are in scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- build-system, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100