CalcSnippets
Mobile Development 4 min read

Flutter iOS Build Fails After `pod install`: Compare the Lockfile and Xcode

A successful local CocoaPods resolution may still disagree with CI or the archived Xcode project. Compare the lockfile, workspace, and selected Xcode before cleaning.

Separate dependency resolution from project selection

Flutter iOS projects use CocoaPods to integrate native plugin dependencies. After pod install, open the .xcworkspace, not only the .xcodeproj; the workspace contains the Pods integration. In CI, confirm the archive command uses the same workspace and scheme that you tested locally.

Start by checking the resolved dependencies and toolchain:

cd ios
pod --version
xcodebuild -version
git diff -- Podfile.lock

If Podfile.lock changed unexpectedly, inspect the exact pod versions and repository source changes. Do not delete the lockfile just to make resolution succeed; that converts a reproducible build into an unreviewed update.

Clean only the layer the evidence points to

When CocoaPods reports a missing or incompatible specification, update the spec repository or review the dependency constraint. When Xcode cannot find a Pods target or generated xcconfig, verify pod install ran in the correct directory and that the workspace is being built. When compilation fails inside a pod, the issue may instead be a deployment target or compiler compatibility boundary.

Use flutter build ios --no-codesign to separate compilation from signing on a machine without release credentials. If that passes but archive fails, focus on signing settings and schemes rather than repeating pod cleanup. On CI, pin or record Xcode and CocoaPods versions so a runner image change is visible.

After a deliberate pod update, build the same simulator and archive configurations used by the team, inspect the lockfile diff, and commit it with the plugin change. A green pod install proves only that dependencies resolved, not that the application archive is correct.

Compare the complete CocoaPods toolchain

A lockfile mismatch is often a symptom of different environments, not a reason to immediately regenerate dependencies. Record the Xcode version, Ruby version, CocoaPods version, Flutter version, and the directory from which pod install ran. A developer using a globally installed CocoaPods release can resolve the same Podfile differently from Bundler-managed CI. If the repository has a Gemfile, use its declared toolchain consistently and commit the bundle lockfile according to the team's policy.

Confirm that Podfile.lock is present in the checkout and that CI is not deleting it during setup. Check whether a plugin or Flutter upgrade intentionally changed pod constraints. Review the diff for additions, removals, source changes, and version movement. A lockfile that changes hundreds of entries after a small plugin update deserves investigation; it may indicate a tool version or spec repository difference rather than the intended dependency change.

Reproduce from the workspace used by the build

The .xcodeproj and .xcworkspace are not interchangeable after CocoaPods integration. Use the workspace generated for the current checkout and the scheme that the archive job actually builds. Confirm that the Pods project and generated configuration files exist after installation. If Xcode reports a missing base configuration, inspect the target's configuration reference and ensure the build did not open a stale workspace from another directory.

Use flutter build ios --no-codesign as a diagnostic boundary when signing credentials are unavailable. If compilation succeeds but archiving fails, focus on scheme configuration, certificates, provisioning, or export options. If compilation fails inside a pod, compare the pod's supported Swift version and deployment target with the active Xcode project. Repeating pod install cannot correct an incompatible compiler setting.

After an intentional dependency update, run a clean checkout test in CI or a separate worktree. Do not remove lockfiles or shared caches as a routine pre-build step. The goal is to prove that the declared dependencies and selected workspace are sufficient to reproduce the app archive, while keeping enough logs to identify exactly which layer fails.

When a mismatch appears only on one developer machine, compare the lockfile from a clean clone rather than accepting a locally regenerated version immediately. Confirm that the machine is using the workspace inside the current checkout and not an old generated iOS directory. Record the exact failing Xcode action and target; a Pods integration error during simulator build is not equivalent to a signing failure during archive. Keeping those boundaries clear avoids broad cleanup that destroys evidence.

When the same checkout behaves differently, compare Bundler and CocoaPods resolution before deleting Pods. A clean install can hide an outdated local tool while leaving CI broken. Capture the workspace path, selected scheme, and configuration name in the build log. Reproducibility depends on both the dependency graph and the Xcode target that consumes it.

Keep reading

Related guides