# Sửa lỗi ITMS-90034 “Missing or invalid signature”

> ITMS-90034: build của bạn không được ký bằng chứng chỉ phân phối hợp lệ. Hãy đọc chữ ký bằng codesign, rồi build lại bản store với EAS.

Trang gốc: [Sửa lỗi ITMS-90034 “Missing or invalid signature”](https://devoria.fr/vi/blog/itms-90034-missing-invalid-signature)
Tác giả: [Mehdi Azizi](https://devoria.fr/vi/mehdi-azizi)
Ngày đăng: 2026-11-04
Lần sửa nội dung gần nhất: 2026-11-04


ITMS-90034 xuất hiện khi bạn gửi build lên App Store Connect. Lỗi này cho biết app của bạn, hoặc một thành phần của nó, không được ký bằng chứng chỉ nộp app (submission certificate) của Apple, tức là một chứng chỉ phân phối hợp lệ. **Cách sửa: tìm ra bundle nào bị ký sai và vì sao, rồi build lại một bản được ký cho App Store.**

Bài này chỉ tập trung vào lỗi đó. Nếu bạn còn mơ hồ về chứng chỉ và profile, hãy đọc trước bài [chứng chỉ nhà phát triển iOS và provisioning profile](https://devoria.fr/vi/blog/ios-developer-certificate-provisioning-profile-expo). Ở đây bạn sẽ có: cách đọc thông báo lỗi, một cây quyết định, các lệnh để kiểm tra file IPA và cách sửa với thông tin xác thực do EAS quản lý. Với phần EAS, mình đã đọc mã nguồn của EAS CLI 24.10.0, chỗ nó chọn chứng chỉ.

## Lỗi ITMS-90034 nghĩa là gì?

Đây là dạng thường gặp của nó, với tên ví dụ:

> ITMS-90034: Missing or invalid signature. The bundle 'com.example.myapp' at bundle path 'Payload/MyApp.app' is not signed using an Apple submission certificate.

Năm 2026, trên diễn đàn của Apple, lỗi này còn xuất hiện dưới dạng "Validation failed (409) Missing or invalid signature", theo sau là cùng đoạn văn bản và "(ID: 90034)".

"Chứng chỉ nộp app" chính là chứng chỉ phân phối (distribution certificate). [Trang trợ giúp của Apple về chứng chỉ](https://developer.apple.com/help/account/certificates/certificates-overview) ghi rõ: chứng chỉ phát triển dùng để chạy app trên thiết bị của bạn, chứng chỉ phân phối dùng để phân phối app hoặc gửi lên App Store Connect.

**Hãy đọc đường dẫn được nêu: nó chỉ ra bundle bị lỗi.** `Payload/MyApp.app` là chính app. Đường dẫn kết thúc bằng `.appex` là một extension, ví dụ widget. Đường dẫn kết thúc bằng `.framework` là một thư viện được nhúng.

Đây không phải là từ chối của reviewer. Bước kiểm tra này diễn ra lúc gửi hoặc khi build đang được xử lý, trước TestFlight: build này sẽ không bao giờ đến tay tester của bạn.

## Cây quyết định: từ thông báo lỗi đến cách sửa

Mỗi dòng tương ứng với một dấu hiệu bạn đọc được trong thông báo lỗi, trong các lệnh ở phần sau hoặc trong log của EAS. Xét lần lượt từ trên xuống: dòng đầu tiên khớp chính là hướng xử lý của bạn.

| Điều bạn thấy                 | Nguyên nhân có thể    | Cách sửa                |
| ----------------------------- | --------------------- | ----------------------- |
| Đường dẫn `.appex`            | Extension ký sai      | Khai báo extension      |
| `Signature=adhoc`             | Build không được ký   | Build với profile store |
| `Apple Development`           | Build phát triển      | Build với profile store |
| Đọc được `ProvisionedDevices` | Build nội bộ (ad hoc) | Build với profile store |
| `sealed resource`             | IPA bị sửa sau khi ký | Build lại               |
| EAS: "no longer valid"        | Chứng chỉ bị thu hồi  | Tạo chứng chỉ mới       |
| Mọi thứ đều hợp lệ            | Sự cố phía Apple      | Gửi lại, rồi báo lỗi    |

## Kiểm tra IPA bằng bốn lệnh

Tải IPA từ trang build trên expo.dev, rồi mở terminal trên máy Mac.

**1. Ai đã ký app?**

```bash
unzip -q MyApp.ipa -d ipa
codesign -dv --verbose=4 ipa/Payload/*.app 2>&1 | grep -E "^(Identifier|Authority|Signature|TeamIdentifier)="
```

`codesign` ghi ra luồng lỗi, nên mới có `2>&1`. Theo [ghi chú kỹ thuật TN3161 của Apple](https://developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates), mỗi dòng `Authority` là một mắt xích của chuỗi tin cậy. Dòng đầu tiên phải bắt đầu bằng `Apple Distribution:` hoặc `iPhone Distribution:`, theo sau là tên team của bạn. Nhãn thứ hai là của loại iOS Distribution cũ: theo mã nguồn, EAS CLI 24.10.0 vẫn tạo chứng chỉ loại này. Nếu bạn thấy `Apple Development:`, đó là build phát triển. Nếu bạn thấy `Signature=adhoc` mà không có dòng `Authority` nào, binary không được ký bởi chứng chỉ nào cả.

**2. App có bị sửa sau khi ký không?**

```bash
codesign --verify --deep --strict -vv ipa/Payload/*.app
```

Kết quả bạn muốn thấy là `valid on disk`, rồi `satisfies its Designated Requirement`. TN3161 nói rõ phép kiểm tra này đảm bảo gì: mọi file cần có đều có mặt, không file nào bị thêm vào, không file nào bị sửa. Với một bundle thử nghiệm mình đã ký rồi chỉnh sửa, lệnh trả về `a sealed resource is missing or invalid`, rồi `file modified:` kèm file bị thay đổi. Tùy chọn `--deep` ở đây chỉ dùng để kiểm tra, không bao giờ dùng để ký: trên diễn đàn của Apple, một kỹ sư của đội hỗ trợ khuyên không nên dùng nó khi ký.

**3. Profile nào được nhúng vào?**

```bash
security cms -D -i ipa/Payload/*.app/embedded.mobileprovision -o profile.plist
plutil -extract ProvisionedDevices xml1 -o - profile.plist
plutil -extract ExpirationDate raw profile.plist
```

Đây là các lệnh trong [ghi chú TN3125 về profile](https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles). Profile App Store không chứa danh sách thiết bị nào: dòng thứ hai phải trả về `Could not extract value`. Nếu nó hiện ra các mã định danh thiết bị, đó là profile ad hoc, của một build nội bộ. Dòng thứ ba cho biết ngày hết hạn của profile.

**4. Extension và framework có được ký giống nhau không?**

```bash
find ipa/Payload/*.app \( -name "*.appex" -o -name "*.framework" \) \
  -exec sh -c 'echo "$1"; codesign -dvv "$1" 2>&1 | grep -m1 "^Authority="' _ {} \;
```

Mỗi thành phần phải hiện cùng dòng `Authority` với app. Nếu có thành phần nào khác đi, đó chính là cái mà thông báo lỗi nhắc đến.

Nếu muốn kiểm tra trước khi gửi, TN3161 khuyên dùng `altool`, cùng phép kiểm tra với nút Validate App của Xcode. Nó cần một API key của App Store Connect, với file `AuthKey_<KEY_ID>.p8` đặt trong `~/.appstoreconnect/private_keys`:

```bash
xcrun altool --validate-app -f MyApp.ipa -t ios --api-key <KEY_ID> --api-issuer <ISSUER_ID>
```

## Sửa với EAS, theo từng nguyên nhân

### Gửi nhầm build nội bộ hoặc build phát triển lên Apple

Theo [tài liệu của Expo về eas.json](https://docs.expo.dev/build/eas-json/), build với `"distribution": "internal"` không được ký cho store: chúng dùng profile ad hoc. Chỉ profile có distribution là `store`, giá trị mặc định, mới tạo ra build gửi được. **Cách an toàn nhất là gửi đúng build bạn vừa tạo, không chọn tay**:

```bash
eas build --platform ios --profile production --auto-submit
```

Nếu bạn dùng `eas submit --path`, hãy kiểm tra file đó đúng là build store mới nhất của bạn. Trên diễn đàn của Apple, một team phát hiện công cụ gửi của họ lần nào cũng gửi lại một file IPA cũ được lưu trong git.

### Quên khai báo extension

Mỗi extension là một bundle riêng, có mã định danh và profile riêng. Trong một dự án Expo dùng native generation, [trang của Expo về extension iOS](https://docs.expo.dev/build-reference/app-extensions/) yêu cầu khai báo chúng trong `extra.eas.build.experimental.ios.appExtensions`. Khi đó EAS CLI biết đến chúng trước khi build, và tạo hoặc kiểm tra thông tin xác thực cho chúng. Phần lớn thư viện có thêm extension sẽ tự viết khai báo này cho bạn qua plugin của chúng.

Solys, app báo thức kèm mini game của mình, có bốn extension: một widget và ba extension Screen Time. Cả bốn đều được khai báo trong cấu hình, và EAS có một profile cho từng cái. **Một extension thêm tay trong Xcode mà không có khai báo này là ứng viên hàng đầu** cho một đường dẫn `.appex` trong thông báo lỗi.

### Chứng chỉ bị thu hồi hoặc hết hạn

[Trang của Apple về chứng chỉ](https://developer.apple.com/support/certificates/) nói rõ: bạn không thể gửi build được ký bằng chứng chỉ đã hết hạn hoặc bị thu hồi. Một build đã gửi nhưng chưa nộp duyệt thậm chí có thể chuyển sang Invalid Binary nếu chứng chỉ của nó bị thu hồi.

Mã nguồn EAS CLI 24.10.0 cho thấy khi nào trường hợp này bị bỏ qua:

- **Build tương tác, có đăng nhập Apple**: EAS so sánh chứng chỉ của nó với các chứng chỉ còn hợp lệ phía Apple. Nếu không còn, nó hiện "Current distribution certificate is no longer valid in Apple Dev Portal" và đề nghị bạn chọn hoặc tạo một cái khác.
- **Build tương tác, không đăng nhập**: EAS chỉ kiểm tra ngày tháng và cảnh báo rằng nó bỏ qua bước xác thực phía Apple.
- **Build không tương tác, trong CI**: EAS hiện "Distribution Certificate is not validated for non-interactive builds" và vẫn ký.

**Trong CI, EAS không kiểm tra lại bản thân chứng chỉ: việc thu hồi có thể chỉ lộ ra lúc gửi.** Cách sửa: chạy một build tương tác có đăng nhập tài khoản Apple, hoặc dùng `eas credentials --platform ios`, menu Build Credentials, rồi "Distribution Certificate: Add a new one to your account". Các profile chứa chứng chỉ cũ sẽ trở nên không hợp lệ: EAS kiểm tra chúng ở lần build sau và tạo lại. Giới hạn của Apple về số lượng chứng chỉ được trình bày chi tiết trong [bài về chứng chỉ nhà phát triển iOS](https://devoria.fr/vi/blog/ios-developer-certificate-provisioning-profile-expo).

### Binary bị sửa sau khi ký

Chữ ký niêm phong mã, tài nguyên và metadata bằng các mã băm, như [ghi chú TN3126 của Apple](https://developer.apple.com/documentation/technotes/tn3126-inside-code-signing-hashes) giải thích. Giải nén IPA để sửa một file rồi nén lại sẽ phá vỡ lớp niêm phong này. **Hãy sửa trong cấu hình, rồi build lại.** Đừng bao giờ chỉnh sửa file IPA do EAS tạo ra.

Cùng logic đó với mã đặt sai chỗ, ví dụ trong một file `.zip`: App Store không thể ký lại nó. Apple mô tả các vị trí được phép trong trang về [nội dung của một bundle](https://developer.apple.com/documentation/bundleresources/placing-content-in-a-bundle).

### Thông tin xác thực cục bộ

Nếu profile EAS của bạn dùng `"credentialsSource": "local"`, file `credentials.json` sẽ trỏ đến một chứng chỉ `.p12` và một profile `.mobileprovision`. Kiểm tra profile bằng các lệnh ở bước 3: nó phải là loại App Store và chứa chứng chỉ phân phối hiện tại của bạn. Và giữ các file này ngoài repo, giống như [API key của một app Expo](https://devoria.fr/vi/blog/khoa-api-bi-mat-app-expo).

### Khi mọi thứ đều hợp lệ

Còn một trường hợp gây bực bội. Trên diễn đàn của Apple, có developer thấy lỗi biến mất khi gửi lại đúng build đó mà không đổi gì. Vào tháng 8 và tháng 9 năm 2026, hai chủ đề mô tả điều ngược lại: chứng chỉ và profile mới, chữ ký đã kiểm tra, vẫn thất bại. Ở một trong hai, một kỹ sư Apple khuyên gửi báo cáo lỗi kèm IPA, kết quả phân tích chữ ký và log của Transporter, rồi liên hệ App Store Connect.

Vậy hãy gửi lại một lần với số build mới. Nếu lỗi vẫn quay lại trong khi bốn lệnh của bạn đều sạch, hãy báo cho Apple với các thông tin đó. **Đừng thu hồi chứng chỉ theo phản xạ**: việc đó không giải quyết thêm gì mà còn làm profile của bạn mất hiệu lực.

## Gửi build mà không gặp bất ngờ

Kiểm tra chữ ký chỉ mất hai phút trước khi gửi. Các bước kiểm tra tự động khác cũng cần sự cẩn thận tương tự, như [ITMS-90725](https://devoria.fr/vi/blog/itms-90725-sdk-version-issue-expo) về phiên bản Xcode hay [ITMS-90683](https://devoria.fr/vi/blog/itms-90683-missing-purpose-string-expo) về câu giải thích quyền truy cập. Toàn bộ quy trình từ build đến gửi, không cần Mac, có trong bài [phát hành app iOS không cần Mac](https://devoria.fr/vi/blog/phat-hanh-app-ios-khong-can-mac-expo-eas).

Bị reviewer từ chối thì cần nhìn rộng hơn: cách xử lý nằm ở trang [app bị Apple từ chối](https://devoria.fr/vi/expertise/ung-dung-bi-apple-tu-choi), và các lý do phổ biến nhất nằm trong bài [vì sao Apple từ chối app](https://devoria.fr/vi/blog/apple-tu-choi-app-5-ly-do-thuc-te).

Để kiểm tra hồ sơ trước khi gửi, [Review Kit](https://devoria.fr/vi/kits/app-review) gồm checklist của mình và các skill Claude Code đọc lại dự án của bạn. Nếu bạn bị kẹt khi gửi và muốn có người xem giúp, [đặt một giờ với mình](https://devoria.fr/vi/coaching): mình sẽ cùng xem dự án qua video call, ngay trên màn hình của bạn. Còn nếu bạn đang chuẩn bị ra mắt app đầu tiên, [làm bài chẩn đoán miễn phí](https://devoria.fr/vi/diagnostic): nó sắp xếp lại các bước theo đúng thứ tự và gửi cho bạn checklist chống bị Apple từ chối của mình.

## Câu hỏi thường gặp

### ITMS-90034 có phải là bị App Review từ chối không?

Không. Đây là bước kiểm tra tự động khi gửi build, trước TestFlight và trước mọi đợt duyệt. Chưa ai mở app của bạn: Apple chỉ thấy rằng chữ ký của nó không đến từ một chứng chỉ phân phối hợp lệ.

### Có cần thu hồi chứng chỉ phân phối để sửa ITMS-90034 không?

Chỉ khi nó bị lộ hoặc đã không còn hợp lệ. Thu hồi một chứng chỉ đang hoạt động sẽ làm profile của bạn mất hiệu lực mà không sửa được nguyên nhân. Hãy bắt đầu bằng việc đọc chữ ký IPA bằng `codesign`, rồi sửa đúng chỗ mà cây quyết định chỉ ra.

### Có thể sửa ITMS-90034 bằng cập nhật từ xa không?

Không. Chữ ký là một phần của binary, và build bị từ chối sẽ không bao giờ dùng được. Bạn phải tạo một binary mới được ký đúng và gửi lại.

### Vì sao lỗi nhắc đến widget chứ không phải app của tôi?

Vì widget là một bundle riêng, được ký bằng profile riêng. Nếu nó không được khai báo với EAS hoặc được ký theo cách khác, nó làm hỏng toàn bộ lần gửi. Hãy khai báo extension trong cấu hình rồi build lại.

### Phải làm gì nếu codesign báo mọi thứ đều hợp lệ?

Kiểm tra thêm profile được nhúng và từng extension. Nếu tất cả đều sạch, hãy gửi lại một lần với số build mới. Nếu lỗi vẫn còn, gửi báo cáo cho Apple kèm IPA, kết quả của `codesign` và log gửi build.


## Dự án của bạn

[Review Kit](https://devoria.fr/vi/kits/app-review): Checklist duyệt App Store của mình, các lần Apple từ chối đã sửa, checklist Google Play và ba skill Claude Code. 1.399.000 ₫.

[iOS & Android Kit](https://devoria.fr/vi/kits/ios): Tạo app iPhone và Android với Claude Code: code khởi đầu từ các app của mình, lộ trình đến tận store và tất cả các kit. 2.799.000 ₫.

[Chẩn đoán: điều gì ngăn bạn có app iPhone](https://devoria.fr/vi/diagnostic): 7 câu hỏi, 60 giây: bạn biết điều gì thật sự cản bạn đăng app iPhone, lộ trình 4 bước và kit phù hợp với bạn.
