XcodeGen version
Burned first recorded this output on 2026-07-14, when 2.45.4 was the current release. The 2.46.0 source still passes nested target attributes through ProjectAttribute(any:); I am adding exact version output to the downstream CI reproduction and will comment with that result.
Minimal project spec
name: CapabilityRepro
targets:
CapabilityRepro:
type: application
platform: iOS
attributes:
SystemCapabilities:
com.apple.HealthKit:
enabled: 1
Actual generated project.pbxproj
SystemCapabilities = "[\"com.apple.HealthKit\": [\"enabled\": 1]]";
The nested dictionary is emitted as a quoted Swift dictionary description. Xcode expects SystemCapabilities to be a PBX dictionary, so a downstream post-generation hook currently has to replace it.
Expected output
SystemCapabilities = {
com.apple.HealthKit = {
enabled = 1;
};
};
Downstream context
The tracked workaround is in codesmithing-dev/Burned#67. It validates the exact malformed shape before rewriting it and will deliberately fail once XcodeGen emits the native PBX dictionary so the hook can be retired.
XcodeGen version
Burned first recorded this output on 2026-07-14, when 2.45.4 was the current release. The 2.46.0 source still passes nested target attributes through
ProjectAttribute(any:); I am adding exact version output to the downstream CI reproduction and will comment with that result.Minimal project spec
Actual generated
project.pbxprojThe nested dictionary is emitted as a quoted Swift dictionary description. Xcode expects
SystemCapabilitiesto be a PBX dictionary, so a downstream post-generation hook currently has to replace it.Expected output
Downstream context
The tracked workaround is in codesmithing-dev/Burned#67. It validates the exact malformed shape before rewriting it and will deliberately fail once XcodeGen emits the native PBX dictionary so the hook can be retired.