Summary
When a target declares a top-level resources: key and has more than one sources: entry (or a single sources: entry whose directory contains subdirectories), the files listed under resources: are silently dropped from the generated project — no PBXBuildFile/PBXResourcesBuildPhase entries are created for them at all. xcodegen generate exits 0 with no warning or error, and the resulting Xcode project builds successfully, but the resource files are simply missing from the app bundle at runtime.
This is a nasty failure mode because there's no diagnostic of any kind — I only found it because our app crashed on launch with Could not locate configuration file: 'GoogleService-Info.plist' (Firebase), even though the file was present on disk and listed under resources: in project.yml.
Environment
- XcodeGen 2.46.0 (Homebrew)
- macOS 26.6.2, Xcode 26.6 (17F113)
Minimal reproduction
Sources/App/App.swift
Sources/Models/Model.swift
Resources/config.plist
project.yml
project.yml:
name: Demo
options:
deploymentTarget:
iOS: "17.0"
targets:
Demo:
type: application
platform: iOS
sources:
- path: Sources/App
- path: Sources/Models
resources:
- path: Resources
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: com.example.demo
GENERATE_INFOPLIST_FILE: YES
Run xcodegen generate, then:
grep -c "config.plist" Demo.xcodeproj/project.pbxproj
# => 0
config.plist does not appear anywhere in the generated project.pbxproj — no file reference, no build file, no resources build phase entry. No error or warning is printed during generation.
Workaround
Removing the resources: key and instead adding the resources folder as one more entry in the sources: array makes it work correctly (XcodeGen auto-classifies non-compilable extensions like .plist into the Resources build phase):
sources:
- path: Sources/App
- path: Sources/Models
- path: Resources
grep -c "config.plist" Demo.xcodeproj/project.pbxproj
# => 4 (file reference + build file + 2 group listings)
Notes on what does/doesn't trigger it, from bisecting:
resources: + a single, flat sources: entry (no subdirectories) → works fine.
resources: + a single sources: entry whose directory contains subdirectories → broken (0 matches).
resources: + two or more sources: entries (even flat, sibling directories) → broken (0 matches).
- Moving the resources path into
sources: instead of resources: → always works, regardless of how many other sources: entries exist.
This doesn't seem related to defaultSourceDirectoryType: syncedFolder (not used here, plain group-type sources) so I don't think it's the same as #1586 — that one was specific to synced folders and was fixed by #1587, but this reproduces with plain path-based sources on a fresh 2.46.0 install.
Impact
Since this fails silently (no error, no warning, successful build), it's easy to ship an app missing critical bundled resources without noticing until a runtime crash or missing-asset bug shows up. Given how common it is to have more than one sources: path in a real project, this seems worth flagging even though there's a simple workaround once you know about it.
Happy to provide more detail or test a fix if useful.
Summary
When a target declares a top-level
resources:key and has more than onesources:entry (or a singlesources:entry whose directory contains subdirectories), the files listed underresources:are silently dropped from the generated project — noPBXBuildFile/PBXResourcesBuildPhaseentries are created for them at all.xcodegen generateexits 0 with no warning or error, and the resulting Xcode project builds successfully, but the resource files are simply missing from the app bundle at runtime.This is a nasty failure mode because there's no diagnostic of any kind — I only found it because our app crashed on launch with
Could not locate configuration file: 'GoogleService-Info.plist'(Firebase), even though the file was present on disk and listed underresources:inproject.yml.Environment
Minimal reproduction
project.yml:Run
xcodegen generate, then:config.plistdoes not appear anywhere in the generatedproject.pbxproj— no file reference, no build file, no resources build phase entry. No error or warning is printed during generation.Workaround
Removing the
resources:key and instead adding the resources folder as one more entry in thesources:array makes it work correctly (XcodeGen auto-classifies non-compilable extensions like.plistinto the Resources build phase):Notes on what does/doesn't trigger it, from bisecting:
resources:+ a single, flatsources:entry (no subdirectories) → works fine.resources:+ a singlesources:entry whose directory contains subdirectories → broken (0 matches).resources:+ two or moresources:entries (even flat, sibling directories) → broken (0 matches).sources:instead ofresources:→ always works, regardless of how many othersources:entries exist.This doesn't seem related to
defaultSourceDirectoryType: syncedFolder(not used here, plaingroup-type sources) so I don't think it's the same as #1586 — that one was specific to synced folders and was fixed by #1587, but this reproduces with plain path-based sources on a fresh 2.46.0 install.Impact
Since this fails silently (no error, no warning, successful build), it's easy to ship an app missing critical bundled resources without noticing until a runtime crash or missing-asset bug shows up. Given how common it is to have more than one
sources:path in a real project, this seems worth flagging even though there's a simple workaround once you know about it.Happy to provide more detail or test a fix if useful.