eas submit iOS 오류 해결: 자주 나오는 에러와 수정 방법
글: Mehdi Azizi
게시, 10분
eas submit이 실패하나요? EAS와 App Store Connect의 실제 메시지, 원인, 해결법을 정리했어요. ascAppId, API 키, Apple 계약, ITMS 코드까지 다뤄요.
eas submit --platform ios가 실패하면, 메시지가 거의 항상 어디를 봐야 하는지 알려줘요. EAS 설정이 불완전하거나, Apple 계정이 막혀 있거나, Apple이 바이너리를 거부한 경우예요. 앞의 두 경우는 새 빌드 없이 몇 분이면 고쳐져요. 세 번째는 ITMS 코드로 알아볼 수 있고, 거의 항상 새 빌드가 필요해요.
저는 Solys, TradaZen, Nolera 같은 iOS 앱을 Expo와 EAS로 출시하고 있어요. 여기 인용한 메시지는 Expo 공식 GitHub 저장소에 있는 EAS CLI 소스 코드에서 그대로 복사했고, 2026년 11월 3일에 다시 확인했어요. 예전 Expo 포럼은 이제 Discord로 연결되기 때문에, 코드가 가장 확실한 출처예요. eas.json 파일부터 심사 제출까지 전체 과정은 먼저 EAS Submit iOS: Expo 앱을 App Store에 출시하기를 읽어 보세요. 여기서는 고치는 데 집중할게요.
eas submit이 하는 일과 필요한 것
Expo 문서에 따르면, 이 명령은 .ipa 파일을 App Store Connect로 보내요. Apple이 처리하고 나면 빌드가 TestFlight에 나타나는데, 보통 10분에서 15분 걸려요. 앱을 심사에 제출하지는 않아요. 그건 App Store Connect에서 직접 해야 해요.
Expo의 iOS 제출 페이지는 세 가지 사전 조건을 들어요.
- 유료 Apple Developer 계정: App Store로 보내려면 반드시 필요해요.
- 번들 식별자:
ios.bundleIdentifier에 넣어요. - EAS CLI 설치와 Expo 계정 로그인.
상호작용 없이 보내려면 같은 페이지에서 두 가지 설정을 더 요구해요.
ascAppId:eas.json의submit프로필에 넣는, App Store Connect 앱 항목 번호예요.- App Store Connect API 키: EAS가 관리하거나 직접 제공해요. 생성, 역할, 폐기 방법은 App Store Connect API 키(.p8)에 자세히 정리했어요.
최소 프로필은 몇 줄이면 돼요. 값은 가짜예요.
{
"submit": {
"production": {
"ios": {
"ascAppId": "1234567890"
}
}
}
}
EAS가 이미 API 키를 갖고 있다면 이 프로필로 충분해요. 제 앱 대부분이 그래요.
메시지 읽기: 세 가지 오류 유형
해결책을 찾기 전에, 명령이 어느 시점에서 멈췄는지부터 확인하세요. 이 표는 제가 실패할 때마다 쓰는 기준이에요.
| 실패 시점 | 유형 | 새 빌드? |
|---|---|---|
| 전송 전 | EAS 설정 | 아니요 |
| Apple 연결, 앱 항목 생성 | Apple 계정 | 아니요 |
| 전송 후, ITMS-90xxx 코드 | 바이너리 거부 | 거의 항상 |
자세한 내용은 Expo 대시보드의 제출 페이지에서 볼 수 있어요. Expo는 거기서 로그를 읽고, 흔한 실패 원인을 알려주는 "Build Annotations" 말풍선을 찾아보라고 권해요. 터미널에서는 EAS CLI 레퍼런스에 따라 --verbose 옵션을 쓰면 EAS Submit 로그가 항상 표시돼요.
EAS 설정 오류
"Set ascAppId in the submit profile (eas.json) or re-run this command in interactive mode."
예를 들어 CI에서 --non-interactive로 명령을 실행했는데, 프로필에 ascAppId가 없는 경우예요. 그러면 EAS CLI 코드는 멈춰요. 질문을 할 수도, 대신 앱 항목을 만들 수도 없으니까요.
해결: 앱 항목 번호를 ascAppId에 복사하세요. Expo가 찾는 위치를 알려줘요. App Store Connect에서 앱을 열고 App Information으로 가세요. General Information 아래의 Apple ID 필드로, 10자리 정도의 숫자예요. Apple 이메일 주소도, 번들 식별자도 아니에요.
Nolera에서는 ascAppId가 없을 때 명령이 Apple Developer 세션을 요구했는데, 이 세션은 만료돼요. 번호를 eas.json에 넣은 뒤로는 전송할 때 아무것도 묻지 않아요.
ascAppId는 빌드 후가 아니라 빌드 전에 추가하세요. SDK 57까지는 Expo가 계산하는 핑거프린트에eas.json이 항상 포함돼요. 런타임 버전이fingerprint정책을 따르는 Vigie에서, 빌드 후에 이 번호를 추가했더니 핑거프린트가 바뀌었어요. 그 뒤에 배포한 업데이트는 설치된 빌드에 절대 도달하지 못했을 거예요. SDK 58부터는 Expo 변경 로그에 따르면 기본 핑거프린트 프리셋인balanced가eas.json을 무시해요.
"App Store Connect API Keys cannot be set up in --non-interactive mode."
프로필에 키가 없고, EAS에도 앱에 연결된 키가 없는 경우예요. Expo 설명대로 비대화형 모드에서는 키를 물어볼 수 없어서 이 메시지와 함께 실패해요.
해결 방법은 두 가지예요.
- EAS가 키를 만들고 보관하게 하세요. 내 컴퓨터에서 대화형 모드로
eas credentials --platform ios를 한 번 실행하고, 앱용 App Store Connect API 키를 설정하게 두면 돼요. - 직접 키를 제공하세요.
ascApiKeyPath,ascApiKeyIssuerId,ascApiKeyId에 넣으면 돼요. 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."
변수에 앱 암호가 아닌 다른 값, 흔히 Apple 계정 암호 자체가 들어 있는 경우예요. EAS CLI는 전송 전에 이 형식을 검사해요.
Apple 도움말에 따르면 앱 암호는 이중 인증을 켠 상태에서 account.apple.com의 App-Specific Passwords 항목에서 만들어요. Apple 계정 암호를 바꾸는 순간 폐기돼요. Expo는 이 방식이 기본이자 권장 방식인 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의 역할 표에 따르면 계약에 동의할 수 있는 사람은 계정 소유자, 즉 Account Holder뿐이에요. EAS 코드는 그에게 App Store Connect의 Business 페이지로 가고, Apple이 제시하면 developer.apple.com 계정에서도 처리하라고 안내해요. 그런 다음 명령을 다시 실행하세요. 유료 앱 계약은 별도 가이드가 있어요: App Store Connect의 Paid Apps Agreement.
"App Store Connect rejected the API authentication credentials."
Apple이 401 오류, NOT_AUTHORIZED로 응답한 경우예요. EAS는 세 가지 원인을 들어요. 더 이상 활성 상태가 아닌 키, 다른 App Store Connect 계정의 키, 또는 잘못된 Key ID, 키 내용, Issuer ID예요.
App Store Connect의 Users and Access 메뉴, Integrations 탭에서 두 식별자를 확인하세요. Apple에 따르면 Issuer ID는 페이지 상단에, Key ID는 활성 키 목록에 표시돼요. 폐기된 키는 절대 다시 활성화되지 않아요. Apple은 30일 동안 Revoked 아래에 표시하니까, 새 키를 만들어야 해요.
"App Store Connect app for application identifier … was not found."
ascAppId가 가리키는 앱 항목을 내 키로 찾을 수 없는 경우예요. EAS는 이 번호를 확인하고, 키가 올바른 계정에서 그 앱에 접근할 수 있는지 확인하라고 해요. 이 키로 보이는 앱 몇 개를 나열해 주기도 해요. Apple 전송 도구에서는 같은 문제가 "No suitable application records were found"로 표시돼요.
세 가지 원인이 자주 나오는데, 그중 두 개는 Apple 포럼의 이 스레드에서 확인한 거예요.
- 앱 항목이 없어요. App Store Connect에서 만들거나,
ascAppId를 빼서 명령이 만들게 하세요. - 번호가 다른 계정 것이에요. 다른 팀이나 다른 프로젝트의
ascAppId를 복사했어요. - 사용자가 앱에 접근할 수 없어요. App Manager나 Developer는 일부 앱으로 제한될 수 있어요. 반면 팀 키는 계정의 모든 앱에 접근해요.
"… is not available to team" 또는 "… is not available to provider"
ascAppId가 없어서 EAS가 대신 앱 항목을 만들 때 나오는 메시지예요. 번들 식별자를 이미 다른 팀이 쓰고 있어요. EAS는 앱 설정에서 이를 바꾸고 다시 실행하라고 해요.
"App name "…" is already taken. Using generated name "…""
실패가 아니에요. App Store에서 이름이 이미 쓰이고 있으면 EAS가 무작위 문자 여섯 개를 붙여서 최대 다섯 번까지 다시 시도해요. 나중에 App Store Connect에서 이름을 바꾸면 돼요. 피하고 싶다면 첫 전송 전에 프로필에 appName과 language를 넣으세요. language가 없으면 기본 언어는 en-US예요.
바이너리 오류: ITMS 코드
전송 후 Apple이 빌드를 처리해요. 거부하면 로그에 ITMS 코드가 하나 이상 나와요. EAS 전송 단계가 인식하고 설명해 주는 코드는 다음과 같아요.
| ITMS 코드 | Apple이 거부하는 것 | 해결 |
|---|---|---|
| 90189 | 이미 쓰인 빌드 번호 | autoIncrement |
| 90062, 90186, 90478 | 닫혔거나 이미 지난 버전 | version 올리기 |
| 90683 | 권한 설명 문구 누락 | ios.infoPlist |
| 90725 | 너무 오래된 iOS SDK | iOS 이미지 또는 Expo SDK |
| 90054, 90055 | 대상 앱 항목과 다른 번들 | ascAppId 수정 |
| 90022, 90023, 90391, 90713 | 아이콘 누락 또는 잘못된 선언 | 아이콘 다시 확인 |
| 90771 | 백그라운드 작업 식별자 누락 | ios.infoPlist |
이 메시지들에서 나온 세 가지 참고 사항이에요.
- 빌드 번호는 버전마다 고유해요. 90189에 대해 EAS는
eas.json에"autoIncrement": true를 권해요. 자세한 내용은 빌드 번호와 버전에 있어요. - 90725의 경우 EAS는
eas.json에서 더 최신 iOS 이미지를 고르고, 필요하면 지원되는 Expo SDK로 올리라고 권해요. - 90771의 경우 Info.plist에 백그라운드 모드
processing은 선언했지만BGTaskSchedulerPermittedIdentifiers키가 없는 거예요.
올바른 앱 항목이나 다른 빌드를 지정하면 되는 90054와 90055를 빼면, 수정은 바이너리에 해야 해요. 다시 빌드하고 다시 보내세요. 두 코드는 별도 가이드가 있어요: Expo에서 ITMS-90683, ITMS-90725.
2026년 9월 말, Solys 빌드가 ITMS-90683으로 전달 단계에서 거부됐어요. 설정 파일을 정리하다가 사진 권한 설명 문구를 지웠거든요. Solys는 사진을 쓰지 않지만, 프로젝트의 라이브러리 하나가 iOS Photos API를 호출해요. Apple은 실제 사용이 아니라 바이너리를 분석해요. 그 뒤로는 이런 문구를 절대 지우지 않아요.
Missing Compliance 상태는 전송 오류가 아니에요. 암호화 관련 신고가 빠진 거고, EAS 출시 가이드에서 설명해요.
전송 전 제 체크리스트
ascAppId가submit프로필에 있고, 빌드 전에 추가했어요.- API 키는 EAS가 관리하거나, 세 필드가 저장소 밖에 둔
.p8을 가리켜요. - Account Holder가 App Store Connect에서 최신 계약에 동의했어요.
autoIncrement가 켜져 있고, EAS CLI 12부터 Expo가 권장하는"appVersionSource": "remote"도 설정했어요.version이 마지막으로 승인된 버전보다 높아요.- 바이너리에 있는 민감한 API마다 권한 설명 문구가 있어요.
- 새 앱이라면 첫 전송 전에
appName과language를 넣었어요.
막히지 않고 첫 앱 보내기
이 명령은 한 단계일 뿐이에요. iOS & Android Kit는 구독까지 포함한 제 앱의 Starter Code에서 시작해서, 네 단계로 App Store까지 자기 속도에 맞춰 안내해요.
첫 출시를 준비 중이라면 무료 진단을 받아 보세요. 실제로 무엇이 막고 있는지 알려주고, Apple 리젝 방지 체크리스트도 보내드려요. 앱 페이지, 스크린샷, 심사 통과까지는 App Store에 앱 출시하기 페이지에서 단계별로 다뤄요.
자주 묻는 질문
왜 eas submit이 CI에서만 실패하나요?
--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는 App Store로 앱을 보내려면 유료 Apple Developer 계정을 요구해요. 무료 계정은 내 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를 올린 다음 다시 빌드하세요.

