xcodebuild Export IPA Failure: How to Fix It on a Remote Mac in 2026?

xcodebuild Export IPA Failure: How to Fix It on a Remote Mac in 2026?

Archive marked successful but the export folder is empty? Stop rebuilding. Fix the export stage by reusing the same xcarchive, then verify ExportOptions.plist, signing assets, entitlements, and the remote session that runs xcodebuild.

This guide is for you if SSH or a CI script archives an iOS app successfully but produces no IPA. It also fits maintainers using a remote Mac as a permanent build host and small teams that need to separate Build, Archive, Export, and Upload failures.

Start with the failure boundary, not another build

The fastest way to diagnose xcodebuild export IPA failure is to establish which stage actually failed. Apple documents distribution as a sequence that includes archiving and exporting, so a successful Archive is evidence about the archive stage only; it is not proof that signing and packaging completed. See Apple’s Xcode distribution documentation for the official stage boundary.

Use these four labels in your log:

  • Build: source files are compiled and linked.
  • Archive: a release archive is created at an .xcarchive path.
  • Export: the archive is converted into an IPA or another distribution package.
  • Upload: the resulting build is sent to the distribution service.

A log that ends with ARCHIVE SUCCEEDED can still be followed by an export error. For example, an anonymized run may look like this:

** ARCHIVE SUCCEEDED **
Exporting archive...
error: exportArchive: No profiles for 'com.example.app' were found
Export failed

The project name, Bundle ID, Team ID, certificate name, profile UUID, username, path, and log content should be anonymized before sharing a failure report. These values can expose your release setup.

Before changing anything, preserve:

  • The complete terminal output.
  • The export command.
  • The exact xcarchive path.
  • The Xcode version and active developer directory.
  • The full ExportOptions.plist.
  • The Distribution log from the graphical export, if available.
  • The contents of the failed output directory.

Do not judge the problem by the final exit code alone. The first specific error usually tells you whether the input archive, distribution settings, signing chain, or remote environment is responsible.

First step: freeze one archive and one command

A repeated build changes too many variables. A new source checkout, regenerated archive, changed profile, or different Xcode selection can hide the original fault.

For the first pass, freeze the following:

  1. One known archive.
  2. One target Mac.
  3. One Xcode installation.
  4. One macOS user.
  5. One export configuration.
  6. One output directory with known permissions.

The command should make the three important export inputs visible:

xcodebuild -exportArchive \
  -archivePath "/path/to/App.xcarchive" \
  -exportOptionsPlist "/path/to/ExportOptions.plist" \
  -exportPath "/path/to/export-output"

The option names above are part of the documented command pattern, but supported keys and behaviors can vary by Xcode version. Run this on the target machine before relying on a copied script:

xcodebuild -help

Record the output with the Xcode version. Do not assume that a plist key from an older pipeline remains valid or has the same effect in the current environment.

The export directory should be empty or dedicated to this test. This prevents an old IPA from being mistaken for a newly produced artifact. After the command finishes, check both the exit result and the filesystem:

find "/path/to/export-output" -maxdepth 1 -type f -print

If no IPA exists, continue with the same archive. Do not rebuild yet.

Archive integrity versus export input

An xcarchive is not just a success marker. It contains the archived app, embedded extensions or frameworks, metadata, and signing-related information needed for distribution. If the archive does not contain the expected product, Export cannot repair it.

Check the archive before editing the plist:

  • Confirm that the expected .app exists inside the archive.
  • Confirm that every required extension is present.
  • Check that embedded frameworks and nested code are present.
  • Open the archive’s Info.plist and verify the scheme and configuration metadata.
  • Confirm that the archive was made for a generic device target, not an unsupported simulator destination.
  • Compare the archived Bundle IDs with the intended release identifiers.
  • Inspect the archive’s entitlements before comparing them with profiles.

For a multi-target app, inspect each target separately. A main application can be correctly archived while an extension, App Clip, notification service, or widget has a different Bundle ID or capability set. The export then fails even though the top-level app looks complete.

Use Organizer to run Validate or Distribute App against the same archive. This is not a replacement for the command-line test. It is a comparison point:

  • If Organizer cannot validate the archive, investigate the archive or signing data first.
  • If Organizer exports successfully but xcodebuild fails, compare the selected distribution method, team, profiles, and signing mode.
  • If both fail with the same specific message, the issue is probably in the archive or signing assets rather than SSH alone.

The goal is to classify the archive as either export-eligible or not export-eligible before changing the build.

ExportOptions.plist: matching intent to actual distribution

ExportOptions.plist is a decision file, not a universal template. The method for device testing is not interchangeable with the method used for App Store Connect distribution, and an old plist may silently point to profiles or signing behavior that no longer matches the project.

Compare the file against these questions:

  • Is the intended output for registered-device testing, App Store Connect, or another supported distribution path?
  • Does the team value match the team associated with the archive and signing assets?
  • Is automatic or manual signing being requested?
  • If profiles are mapped manually, does every relevant Bundle ID have the correct profile?
  • Is the output path writable by the user running the command?
  • Are all keys supported by the target Xcode version?

The safest baseline is a successful graphical export from the same archive. Select the intended distribution workflow, save the resulting settings where the tool permits it, and compare them with the script’s plist. This exposes differences that are easy to miss in a hand-written file.

Do not add random keys until the command stops failing. A smaller, version-verified configuration is easier to audit than a large plist copied from an unrelated project.

Use the target machine’s xcodebuild -help output as the local reference. Apple’s Xcode distribution guidance explains the distribution workflow, while the command help shows what the installed tool accepts.

Signing identity, private key, profile, and entitlements

The export stage validates a chain, not a single certificate file. The chain normally includes:

  1. A suitable distribution certificate.
  2. The matching private key in the active Keychain.
  3. A provisioning profile for each relevant Bundle ID.
  4. Entitlements compatible with the profile.
  5. A team and signing-management mode that agree with the archive.

Apple explains the purpose of certificate types in its certificates overview. Importing a certificate file without its matching private key does not give the remote Mac the ability to sign. This is a common reason for local success and remote failure.

Check the signing identity in the same user session that runs the export:

security find-identity -v -p codesigning

The command must show the expected usable identity. A certificate visible in a graphical Keychain window is not enough if the SSH process uses another login context or cannot unlock the relevant Keychain.

Then inspect the profiles available to that user. Confirm that the profile is present, current, and associated with the required Bundle ID. Apple’s guidance for editing, downloading, or deleting provisioning profiles is the appropriate reference before removing or regenerating anything.

Compare:

  • The Bundle ID in the archived app.
  • The Bundle ID in every extension.
  • The application identifier entitlement.
  • Capability entitlements such as push notifications or associated domains.
  • The profile assigned to each target.
  • The signing identity used by the archive and export.

Do not revoke a certificate or delete a profile as the first response. Before any destructive change, export or document the current assets, note which projects use them, and define a rollback path. A replacement profile can affect other release jobs, and a revoked certificate can invalidate a wider signing workflow.

Automatic signing versus manual signing

Automatic signing and manual signing fail in different ways.

With automatic signing, verify that the remote user can access the required development account context and that the project is allowed to update signing assets. A graphical session may have completed an authorization step that an SSH job cannot repeat. Check the account role and project access before treating the failure as a missing file. Apple lists relevant App Store Connect role permissions, but account access and local Keychain access still need separate verification.

With manual signing, make the mapping explicit for the main app and every embedded target. A correct profile for the main Bundle ID does not cover a widget or extension with a different identifier.

Use this comparison before changing the project:

Export path What to verify first Typical next action
Graphical export succeeds, SSH export fails User, Keychain, developer directory, environment, output permissions Reproduce under the SSH user and compare session state
Both graphical and SSH export fail Archive, profiles, certificates, entitlements, distribution method Validate the archive and signing chain
Test-device export succeeds, App Store export fails Distribution method, release profile, capabilities, team mapping Create a separate verified App Store export configuration
Main app exports, extension causes failure Extension Bundle ID, profile, entitlements, nested signing Inspect and map every target independently
Export reports success but no IPA appears Output path, cleanup step, filename assumptions, filesystem permissions Inspect the exact export path before post-processing

This table is a decision tool, not a diagnosis by itself. The first concrete error still controls the next test.

Remote Mac sessions: same machine, different execution state

A local graphical export can succeed while a remote SSH command fails because “the same Mac” does not mean “the same execution context.”

Compare the interactive and unattended sessions under the same macOS user:

whoami
echo "$HOME"
xcode-select -p
pwd
env | sort

Then verify:

  • The active developer directory is the expected Xcode installation.
  • The working directory exists and is readable.
  • The Keychain containing the private key is available.
  • The SSH process can use the signing identity.
  • The profile directory is visible to the process.
  • The temporary directory is writable.
  • The export directory is writable and not cleaned immediately.
  • The job retains logs after failure.
  • A disconnect does not terminate the process before export completes.

Do not assume that a GUI login and SSH share every environment variable, authorization state, Keychain unlock, or shell configuration. Make required paths explicit in the script instead of relying on interactive shell startup files.

If your script uses a cleanup trap, check it before concluding that no IPA was created. A post-export command may delete or move the output after a successful export. Likewise, a relative output path may point somewhere other than the directory you inspected.

Keep the failed archive, plist, log, and output directory until the investigation is complete. Rebooting the remote Mac or cleaning the workspace can remove the evidence needed to distinguish a signing problem from a session problem.

What exit code 70 tells you—and what it does not

When xcodebuild exportArchive returns exit code 70, treat the code as a result category rather than a universal explanation. It does not, by itself, tell you whether the problem is a profile, certificate, entitlement, plist key, archive, or permission issue.

Use this sequence:

  1. Locate the first detailed error before the exit code.
  2. Confirm that the archive path points to the intended file.
  3. Run the same command without changing the archive.
  4. Compare the plist with a successful graphical export.
  5. Check signing identity and private-key access under the task user.
  6. Inspect every target’s profile and entitlements.
  7. Compare the SSH environment with the graphical environment.
  8. Preserve the new log and classify the result.

Apple’s official documents define the supported distribution and signing concepts, but they do not turn one exit code into a single fix. Community reports can reveal useful symptoms, yet an individual forum case is not a general rule. Your own archive, command, Xcode help output, and logs remain the authoritative evidence for this machine.

FAQ: remote IPA export checks

Why is there no IPA after Xcode Archive succeeds?

Archive and Export are separate operations. The archive may be valid while the export method, provisioning profile, signing identity, entitlements, or output directory is invalid. Reuse the same xcarchive and inspect the first export error before rebuilding. This keeps the investigation focused on the failed stage instead of replacing a potentially good archive.

How should you investigate xcodebuild exportArchive exit code 70?

Treat exit code 70 as a failure signal, not a diagnosis. Read the lines immediately before it, rerun export with the same archive and settings, and compare the command-line result with a graphical export. Then verify the distribution method, Team mapping, profiles, certificates, private keys, and entitlements. The first specific message determines the next check.

How do you verify ExportOptions.plist signing and distribution settings?

Start with a successful graphical export from the same archive, then compare its selected settings with your file. Confirm the intended distribution method, team, signing-management mode, profile mapping, archive path, and output path. Do not copy an old template blindly. Run xcodebuild -help on the target machine and verify each supported key against current documentation.

Why does IPA export work locally but fail over SSH?

A graphical login and an SSH job may use different users, Keychains, developer directories, working directories, environment variables, and temporary paths. Compare both sessions under the same account. Test private-key access, profile visibility, signing authorization, and output-directory permissions. Preserve failed logs and intermediate files before restarting the job or cleaning its workspace.

How can you prove that a remote Mac can export IPAs unattended?

Use one known-good xcarchive and repeat export under the exact unattended command. Check that the expected IPA appears, its signature validates, logs survive a failed run, and the job can resume after a controlled restart. Test interactive and SSH sessions, then record the working user, Keychain state, developer directory, profiles, and output permissions as acceptance evidence.

Acceptance run: prove repeatability before changing infrastructure

A remote Mac is ready for unattended export only when the same archive passes a repeatable evidence check. Do not mark it ready because one graphical export worked.

Run this acceptance sequence:

  1. Create or select one known-good archive.
  2. Record the Xcode version and xcode-select -p result.
  3. Validate the archive in Organizer.
  4. Export it graphically with the intended distribution method.
  5. Save the graphical result and Distribution log.
  6. Run command-line export with the same archive.
  7. Use the verified ExportOptions.plist.
  8. Run the command under the actual SSH or CI user.
  9. Confirm the IPA exists at the expected absolute path.
  10. Inspect the package and preserve its checksum or equivalent release record.
  11. Repeat export without rebuilding.
  12. Perform a controlled task restart and verify that logs and required assets remain available.

The pass condition is not merely “the command returned success.” You need evidence that the output is the expected artifact, the signing chain is usable by the unattended user, the output path is stable, and a failure leaves enough information for recovery.

For longer-lived workflows, connect this runbook to a documented remote Mac build environment and keep signing migration details separate from export diagnosis. If the machine is dedicated to repeated release work, a bare-metal environment may be easier to audit than a shared or highly variable setup; compare the operational trade-offs in this bare-metal versus virtualized macOS overview.

When to keep repairing and when to move the job

Keep repairing the current setup when the same archive exports successfully in a graphical session and the failure is isolated to a clear SSH difference, such as an unavailable private key, wrong developer directory, or unwritable output path. Those are environment defects with a defined correction.

Escalate to a separate remote build environment when:

  • The current Mac mixes several users and signing contexts.
  • Workspace cleanup removes evidence after every failed job.
  • Xcode selection changes between interactive and unattended runs.
  • The machine cannot preserve profiles, private keys, or logs safely.
  • A controlled restart leaves the release job in an unknown state.
  • You need a stable Mac that remains available while your development machine is offline.

A new machine will not fix a bad archive or an invalid ExportOptions.plist. First run the same acceptance sequence on the candidate environment. If the existing setup can export only through a GUI but cannot pass the unattended test, use the results to configure a separate remote Mac rather than repeatedly rebuilding the app.

If your current Windows or Linux workstation depends on a temporary workaround, it also leaves you with no native Xcode session, no local Keychain continuity, and a fragile path for release signing. Renting a Mac through MacDate can be the more controlled option for temporary releases, migration work, or a small team that needs a dedicated remote build host without buying another Mac immediately. Review the available remote Mac configurations, then run your own archive, export, and restart tests before treating the machine as a permanent iOS build server.

The decision is simple: do not rebuild until the archive is proven faulty. Fix the first failed export metric, verify it with the same xcarchive, and accept the remote Mac only after unattended IPA export survives a repeat and a controlled restart.