# eas submit iOS 常见错误及解决方法

> eas submit 失败？逐条解析 EAS 和 App Store Connect 的真实报错、原因与修复：ascAppId、API 密钥、Apple 协议、ITMS 代码。

原始页面：[eas submit iOS 常见错误及解决方法](https://devoria.fr/zh-hans/blog/eas-submit-ios-common-errors-fixes)
作者：[Mehdi Azizi](https://devoria.fr/zh-hans/mehdi-azizi)
发布：2026-11-04
内容最后修订：2026-11-04


当 `eas submit --platform ios` 失败时，报错信息几乎总会告诉你该看哪里。**要么是你的 EAS 配置不完整，要么是你的 Apple 账号卡住了，要么是 Apple 拒绝了二进制文件。**前两种情况几分钟就能修好，不需要重新构建。第三种能从 ITMS 代码认出来，而且几乎总是需要重新构建。

我用 Expo 和 EAS 发布自己的 iOS 应用，包括 Solys、TradaZen 和 Nolera。这里引用的报错信息都摘自 EAS CLI 的源代码，来自 [Expo 官方 GitHub 仓库](https://github.com/expo/eas-cli)，我在 2026 年 11 月 3 日重新核对过。Expo 的旧论坛现在已经转向 Discord：代码仍然是最可靠的来源。如果你想看完整流程，从 `eas.json` 文件一直到提交审核，请先读 [EAS Submit iOS：把 Expo 应用发布到 App Store](https://devoria.fr/zh-hans/blog/eas-submit-ios-publish-expo-app-store)。这篇只讲修复。

## eas submit 做什么，需要什么

根据 [Expo 文档](https://docs.expo.dev/deploy/submit-to-app-stores/)，这条命令会把你的 `.ipa` 文件发送到 App Store Connect。Apple 处理完之后，构建会出现在 TestFlight 里，一般需要 10 到 15 分钟。**它不会把你的应用提交审核**：这一步仍然要你在 App Store Connect 里手动完成。

[Expo 关于 iOS 提交的页面](https://docs.expo.dev/submit/ios/)列出了三个前提条件：

- **付费的 Apple Developer 账号**，任何提交到 App Store 的操作都需要它；
- **bundle identifier**，写在 `ios.bundleIdentifier` 里；
- **已安装 EAS CLI**，并登录你的 Expo 账号。

如果要在无交互模式下提交，同一页面还要求两项设置：

- `eas.json` 的 `submit` 配置中的 **`ascAppId`**，也就是你在 App Store Connect 中应用页面的编号；
- **一个 App Store Connect API 密钥**，可以由 EAS 管理，也可以你自己提供。它的创建、权限角色和撤销方法，详见 [App Store Connect API 密钥（.p8）](https://devoria.fr/zh-hans/blog/app-store-connect-api-key-p8)。

最小配置只需要几行。这里的值是虚构的：

```json
{
  "submit": {
    "production": {
      "ios": {
        "ascAppId": "1234567890"
      }
    }
  }
}
```

如果 EAS 已经保存了你的 API 密钥，这个配置就够了。我的大部分应用都是这样。

## 看懂报错：三类错误

在找修复方法之前，先确认命令是在哪个阶段停下的。下面这张表是我每次失败时都会对照的。

| 失败阶段                       | 类别       | 需要重新构建？ |
| ------------------------------ | ---------- | -------------- |
| 发送任何内容之前               | EAS 配置   | 否             |
| 连接 Apple、创建应用记录       | Apple 账号 | 否             |
| 发送之后，出现 ITMS-90xxx 代码 | 二进制被拒 | 几乎总是       |

详细信息可以在 Expo 控制台中该次提交的页面上查看。[Expo 建议](https://docs.expo.dev/deploy/submit-to-app-stores/)在那里阅读日志，并留意“Build Annotations”提示框，它会标出常见的失败原因。在终端里，根据 [EAS CLI 参考文档](https://docs.expo.dev/eas/cli/)，加上 `--verbose` 选项就会始终显示 EAS Submit 的日志。

## EAS 配置错误

### “Set ascAppId in the submit profile (eas.json) or re-run this command in interactive mode.”

你用 `--non-interactive` 运行了命令（比如在持续集成中），而你的配置里没有 `ascAppId`。这时 [EAS CLI 的代码](https://github.com/expo/eas-cli/blob/main/packages/eas-cli/src/submit/ios/IosSubmitCommand.ts)会直接停止：它既不能向你提问，也不能替你创建应用记录。

**修复方法：把应用记录的编号填进 `ascAppId`。**[Expo 说明了在哪里找到它](https://github.com/expo/fyi/blob/main/asc-app-id.md)：在 App Store Connect 中打开你的应用，然后进入 App Information。它就是 General Information 下的 Apple ID 字段，一个十位左右的数字。它既不是你的 Apple 邮箱地址，也不是你的 bundle identifier。

在 Nolera 上，没有 `ascAppId` 时，命令会要求我登录一个会过期的 Apple Developer 会话。自从把编号写进 `eas.json`，提交时就什么都不用再问了。

> 在构建之前添加 `ascAppId`，不要在构建之后。直到 SDK 57，[Expo 计算的指纹](https://github.com/expo/expo/blob/main/packages/@expo/fingerprint/src/sourcer/Expo.ts)都会包含 `eas.json`。在 Vigie 上，运行时版本采用 `fingerprint` 策略，我在构建之后才加上这个编号，结果指纹变了：之后发布的更新永远不会到达已安装的那个构建。根据 [Expo 的版本更新日志](https://github.com/expo/expo/blob/main/packages/@expo/fingerprint/CHANGELOG.md)，从 SDK 58 起，指纹的默认预设 `balanced` 会忽略 `eas.json`。

### “App Store Connect API Keys cannot be set up in --non-interactive mode.”

你的配置里没有密钥，EAS 也没有为你的应用关联任何密钥。[Expo 明确说明](https://docs.expo.dev/submit/ios/)：在无交互模式下，命令无法向你索取密钥，于是会带着这条信息失败。

有两种修复方法：

- **让 EAS 创建并保存密钥。**在你自己的电脑上，以交互模式运行一次 `eas credentials --platform ios`，让它为你的应用配置一个 App Store Connect API 密钥。
- **使用你自己的密钥**，填在 `ascApiKeyPath`、`ascApiKeyIssuerId` 和 `ascApiKeyId` 里。根据 [eas.json 参考文档](https://docs.expo.dev/eas/json/)，这三个字段都支持环境变量，比如 `$ASC_API_KEY_PATH`。

在我最新的一个应用上，`--auto-submit` 选项想要一个 Apple 账号来创建它的提交密钥。我把自己密钥的三个字段写进了本地工作副本的配置里，从不提交到仓库。然后我用 `--id` 和 `--non-interactive` 发送了已经完成的构建。

### “EXPO_APPLE_APP_SPECIFIC_PASSWORD must be in the format xxxx-xxxx-xxxx-xxxx, where x is a lowercase letter.”

这个变量里放的不是 App 专用密码，常常是你的 Apple 账号密码本身。[EAS CLI](https://github.com/expo/eas-cli/blob/main/packages/eas-cli/src/submit/ios/IosSubmitCommand.ts) 会在发送任何内容之前检查这个格式。

根据 [Apple 帮助文档](https://support.apple.com/en-us/102654)，App 专用密码在 account.apple.com 的 App-Specific Passwords 栏目中生成，前提是开启了双重认证。一旦你修改 Apple 账号密码，它就会被撤销。**Expo 认为这种方式[不如 API 密钥安全](https://github.com/expo/fyi/blob/main/apple-app-specific-password.md)，API 密钥才是它默认且推荐的方式。**

## Apple 账号错误

### “… agree to the latest Program License Agreement in your developer account.”

完整的信息以“You currently don't have access to this membership resource”开头。在 Apple 那边，原始响应可能包含“Unable to process request - PLA Update available”。EAS 较新的提交步骤则会显示“A required Apple agreement is missing or has expired”。

原因都一样：Apple 更新了某份协议，但还没有人接受。根据 [Apple 的角色权限表](https://developer.apple.com/help/account/access/roles/)，**只有账号持有人（Account Holder）才能接受协议**。[EAS 的代码](https://github.com/expo/eas-cli/blob/main/packages/build-tools/src/steps/utils/ios/AscApiClient.ts)会提示他前往 App Store Connect 的 Business 页面，如果 Apple 有提示，再去 developer.apple.com 上的账号页面处理。然后重新运行命令。付费应用协议有专门的指南：[App Store Connect 中的 Paid Apps Agreement](https://devoria.fr/zh-hans/blog/paid-apps-agreement-status-w-8ben-first-payment)。

### “App Store Connect rejected the API authentication credentials.”

Apple 返回了 401 错误，`NOT_AUTHORIZED`。[EAS](https://github.com/expo/eas-cli/blob/main/packages/build-tools/src/steps/utils/ios/AscApiClient.ts) 列出了三个原因：密钥已失效，密钥属于另一个 App Store Connect 账号，或者 Key ID、密钥内容、Issuer ID 有误。

在 App Store Connect 的 Users and Access 菜单、Integrations 标签页里核对这两个标识符。根据 [Apple](https://developer.apple.com/documentation/appstoreconnectapi/generating-tokens-for-api-requests)，Issuer ID 显示在页面顶部，Key ID 显示在有效密钥列表里。**被撤销的密钥永远无法重新启用。**[Apple 会在 Revoked 下显示它](https://developer.apple.com/documentation/appstoreconnectapi/revoking-api-keys) 30 天：你必须生成一个新的。

### “App Store Connect app for application identifier … was not found.”

用你的密钥找不到 `ascAppId` 指向的应用记录。[EAS](https://github.com/expo/eas-cli/blob/main/packages/build-tools/src/steps/utils/ios/AscApiUtils.ts) 会让你检查这个编号，并确认该密钥在正确的账号中确实能访问这个应用。它甚至会列出这个密钥能看到的几个应用。如果用 Apple 自己的上传工具，同样的问题会显示为“No suitable application records were found”。

常见原因有三个，其中两个出自 [Apple 论坛的这个帖子](https://developer.apple.com/forums/thread/106806)：

- **应用记录不存在。**在 App Store Connect 中创建它，或者去掉 `ascAppId`，让命令自动创建。
- **编号来自另一个账号。**你复制了另一个团队或另一个项目的 `ascAppId`。
- **用户没有该应用的访问权限。**App Manager 或 Developer 可能被限制只能访问部分应用。而团队密钥则[可以访问账号下的所有应用](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api)。

### “… is not available to team”或“… is not available to provider”

这条信息出现在缺少 `ascAppId`、由 EAS 替你创建应用记录的时候。这个 bundle identifier 已经被另一个团队占用了。[EAS 会让你](https://github.com/expo/eas-cli/blob/main/packages/eas-cli/src/credentials/ios/appstore/ensureAppExists.ts)在应用配置中修改它，然后重新运行。

### “App name "…" is already taken. Using generated name "…"”

这不是失败。当名称在 App Store 上已被占用时，EAS 会随机加上六个字符重试，最多五次。之后你可以在 App Store Connect 里给应用记录改名。想避免这种情况，在首次提交前就在配置中填好 `appName` 和 `language`：如果没有 `language`，[主语言默认是 `en-US`](https://docs.expo.dev/eas/json/)。

## 二进制错误：ITMS 代码

发送之后，Apple 会处理构建。如果被拒，日志里会出现一个或多个 ITMS 代码。下面是 [EAS 提交步骤](https://github.com/expo/eas-cli/blob/main/packages/build-tools/src/steps/functions/uploadToAsc.ts)能识别并解释的代码：

| ITMS 代码                  | Apple 拒绝的原因            | 修复方法            |
| -------------------------- | --------------------------- | ------------------- |
| 90189                      | 构建号已被使用              | `autoIncrement`     |
| 90062, 90186, 90478        | 版本已关闭或已被超过        | 提高 `version`      |
| 90683                      | 缺少权限说明文字            | `ios.infoPlist`     |
| 90725                      | iOS SDK 过旧                | iOS 镜像或 Expo SDK |
| 90054, 90055               | bundle 与目标应用记录不一致 | 修正 `ascAppId`     |
| 90022, 90023, 90391, 90713 | 图标缺失或声明错误          | 检查图标            |
| 90771                      | 缺少后台任务标识符          | `ios.infoPlist`     |

从这些信息中可以得出三点：

- **每个版本的构建号必须唯一。**针对 90189，EAS 建议在 `eas.json` 中设置 `"autoIncrement": true`。详见 [构建号与版本号](https://devoria.fr/zh-hans/blog/app-store-connect-build-number-version)。
- **针对 90725**，EAS 建议在 `eas.json` 中选择更新的 iOS 镜像，必要时升级到受支持的 Expo SDK。
- **针对 90771**，你的 Info.plist 声明了 `processing` 后台模式，却没有声明 `BGTaskSchedulerPermittedIdentifiers` 键。

除了 90054 和 90055（只需指向正确的应用记录或换一个构建），**修复都涉及二进制文件：重新构建，然后再次提交。**有两个代码有专门的指南：[Expo 下的 ITMS-90683](https://devoria.fr/zh-hans/blog/itms-90683-missing-purpose-string-expo) 和 [ITMS-90725](https://devoria.fr/zh-hans/blog/itms-90725-sdk-version-issue-expo)。

2026 年 9 月底，Solys 的一个构建在交付时因 ITMS-90683 被拒。我在清理配置文件时删掉了一条关于照片的权限说明。Solys 并不使用照片，但项目里的某个库调用了 iOS 的 Photos API。**Apple 分析的是二进制文件，而不是实际用途：**从那以后，我再也不删这些说明文字了。

至于 Missing Compliance 状态，它并不是提交错误。它表示缺少你的加密声明，具体见 [EAS 发布指南](https://devoria.fr/zh-hans/blog/eas-submit-ios-publish-expo-app-store)。

## 我每次提交前的检查清单

- `ascAppId` 已写在 `submit` 配置中，并且是在构建之前加的。
- API 密钥由 EAS 管理，或者它的三个字段指向存放在仓库之外的 `.p8` 文件。
- Account Holder 已在 App Store Connect 中接受最新的协议。
- `autoIncrement` 已开启，并配合 `"appVersionSource": "remote"`，这是 EAS CLI 12 起 [Expo 推荐的做法](https://docs.expo.dev/build-reference/app-versions/)。
- `version` 高于最近一个已获批准的版本。
- 二进制中出现的每个敏感 API 都有对应的权限说明文字。
- 对于新应用，首次提交前已填好 `appName` 和 `language`。

## 顺利提交你的第一个应用

这条命令只是其中一步。[iOS & Android Kit](https://devoria.fr/zh-hans/kits/ios) 以我自己应用的 Starter Code 为基础（包含订阅功能），带你按自己的节奏走完通往 App Store 的四个步骤。

如果你正在准备第一次上架，[来做免费诊断](https://devoria.fr/zh-hans/diagnostic)：它会告诉你真正卡住你的是什么，并把我的 Apple 防拒审清单发给你。关于应用页面、截图和审核，[把应用发布到 App Store](https://devoria.fr/zh-hans/expertise/publish-an-app-on-the-app-store) 这一页逐步讲解了每个环节。

## 常见问题

### 为什么 eas submit 只在持续集成中失败？

在 `--non-interactive` 模式下，命令无法向你提问。它需要配置中的 `ascAppId`，以及一个已经关联到该应用的 API 密钥，或者在 `eas.json` 中填好密钥的三个字段。在你自己的电脑上，它本来会问你这些问题。

### eas submit 出错后需要重新构建吗？

只有当 Apple 以 ITMS 代码拒绝二进制文件时才需要。例外：ITMS-90054 和 90055 表示构建指向了错误的应用记录，只需把它重新发送到正确的记录。配置错误和账号错误可以在 `eas.json`、App Store Connect 或你的 Apple 账号中修复。然后重新发送同一个构建，比如用 `--latest` 或 `--id`。

### 在哪里查看 EAS Submit 的提交日志？

在 Expo 控制台中该次提交的页面上。Expo 建议在那里阅读日志和“Build Annotations”提示框。在终端里，加上 `--verbose` 就会始终显示日志。

### 免费的 Apple 账号能用 eas submit 吗？

不能。Expo 要求使用付费的 Apple Developer 账号才能把应用提交到 App Store。免费账号可以在你自己的 iPhone 上测试，但不能使用 App Store Connect。

### eas submit 用的 API 密钥应该给什么角色？

Expo 的指南给密钥分配的是 Admin 角色。根据 Apple 的角色权限表，App Manager 和 Developer 角色也可以上传构建。我的 Expo 构建用的是 App Manager 角色的团队密钥。只有 Account Holder 和 Admin 才能生成团队密钥。

### EAS 中的“Increment Build Number”是什么意思？

Apple 以 ITMS-90189 代码拒绝了构建：这个构建号在该版本下已经存在。在 `eas.json` 中开启 `"autoIncrement": true`，或者提高 `ios.buildNumber`，然后重新构建。


## 你的项目

[Review Kit](https://devoria.fr/zh-hans/kits/app-review)：我的 App Store 审核清单、我被 Apple 拒审后的修正方案、Google Play 审核清单，以及三个 Claude Code skill。¥369。

[iOS & Android Kit](https://devoria.fr/zh-hans/kits/ios)：用 Claude Code 打造你的 iPhone 和 Android 应用：我自己应用的起步代码、上架商店的完整流程，以及全部工具包。¥739。

[诊断：你离自己的 iPhone 应用还差什么](https://devoria.fr/zh-hans/diagnostic)：7 个问题，60 秒：看清真正阻碍你发布 iPhone 应用的原因，拿到你的 4 步路线和适合你的套件。
