Why does my iOS VPN app with a Network Extension fail to build on Codemagic?

Last updated: August 4, 2026

Context

When building an iOS VPN app that includes a Network Extension target (e.g., using WireGuard), you may encounter several issues, including:

  • Provisioning profile not found for the .network-extension bundle ID

  • Build failures related to the WireGuard Go bridge (WireGuardGoBridgeiOS) or Swift Package Manager manifest version mismatches

  • Archive errors mentioning missing headers such as u_int16_t or PCM compilation failures

Answer

There are several distinct issues that can affect this type of build. Work through each one as applicable:

1. Fix the Swift Package Manager manifest version

If your build fails at xcodebuild -showBuildSettings with errors like 'v12' is unavailable or 'v15' is unavailable in your Vendor/wireguard-apple/Package.swift, the manifest's swift-tools-version is too low. Platform targets such as .macOS(.v12) and .iOS(.v15) require Swift tools version 5.5 or higher.

Fix: Open Vendor/wireguard-apple/Package.swift and ensure the first line reads:

// swift-tools-version:5.5

Commit and push the change, then re-run the build.

2. Set up code signing for multiple bundle IDs (main app + Network Extension)

A provisioning profile existing in the Apple Developer Portal is not enough on its own — it must be fetched onto the build machine. The wildcard match on com.example.app.* only picks up profiles already available to the build; it will not automatically provision the extension target.

The recommended approach is to let Codemagic fetch or create both profiles at build time using the App Store Connect integration. Follow these steps:

  1. Generate a certificate private key on your local machine:

    ssh-keygen -t rsa -b 2048 -m PEM -f ~/Desktop/ios_distribution_private_key -q -N ""

    Open the generated ios_distribution_private_key file, copy its entire contents (including the -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- tags), and save it as an environment variable named CERTIFICATE_PRIVATE_KEY inside a group called code-signing in Codemagic.

  2. Remove any manual ios_signing block from your codemagic.yaml:

    # Remove this block:
    environment:
      ios_signing:
        distribution_type: app_store
        bundle_identifier: com.example.app
  3. Add the App Store Connect integration reference to your workflow. Go to Codemagic app → Teams → General settings → Team integrations → Developer Portal → Manage Keys and copy your API key reference name. Then update your codemagic.yaml:

    ios-workflow:
      name: iOS Workflow
      max_build_duration: 120
      instance_type: mac_mini_m2
      environment:
        groups:
          - code-signing
        vars:
          BUNDLE_ID: com.example.app
      integrations:
        app_store_connect: Your API Key Name
  4. Add the following scripts at the top of your scripts section to initialize the keychain, fetch signing files, and apply profiles:

    scripts:
      - name: Set up keychain
        script: keychain initialize
      - name: Fetch signing files
        script: |
          app-store-connect fetch-signing-files "$BUNDLE_ID" \
            --type IOS_APP_STORE \
            --create
      - name: Set up signing certificate
        script: keychain add-certificates
      - name: Set up code signing settings on Xcode project
        script: xcode-project use-profiles
    # other scripts go here

    Referring to the main bundle ID is generally sufficient — Codemagic will match and apply the correct profiles for associated extension targets.

3. Fix WireGuard Go bridge build errors (missing headers)

If the archive fails with errors referencing WireGuardGoBridgeiOS, PCM compilation failures, or a missing u_int16_t type, this is caused by a missing #include <sys/types.h> in the WireGuard-Apple package source.

Fix: Add the missing include to the relevant WireGuard-Apple source file(s). Check whether you have already applied this fix locally and forgotten to push it to your repository. For reference, see:

Once the fix is committed and pushed, re-run the build on Codemagic.