Compare commits

...
Author SHA1 Message Date
Stanisław Chmiela 378d4161ca [build-tools] Handle ASC app relationship invalid errors 2026-10-23 13:49:04 +02:00
3 changed files with 70 additions and 0 deletions

No files matched your search

@@ -0,0 +1,5 @@
---
'@expo/build-tools': patch
---
Explain invalid app relationships when creating App Store Connect uploads.
@@ -256,6 +256,33 @@ export namespace AscApiUtils {
});
} catch (error) {
const errors = error instanceof AggregateError ? error.errors : [error];
const isInvalidAppRelationshipError =
errors.length > 0 &&
errors.every(item => {
if (
!(item instanceof AscApiRequestError) ||
item.status !== 409 ||
item.code !== 'ENTITY_ERROR.RELATIONSHIP.INVALID'
) {
return false;
}
const source = item.responseJson.source;
return (
typeof source === 'object' &&
source !== null &&
'pointer' in source &&
source.pointer === '/data/relationships/app/data/id'
);
});
if (isInvalidAppRelationshipError) {
throw new UserError(
'EAS_UPLOAD_TO_ASC_INVALID_APP_RELATIONSHIP',
`App Store Connect rejected Apple app identifier ${appleAppIdentifier} while creating the build upload. ` +
'Check the Apple app identifier in the submit profile and make sure the API key can access that app. ' +
'Select the correct submit profile or update the Apple app identifier, then submit again.',
{ cause: error, docsUrl: 'https://expo.fyi/asc-app-id' }
);
}
const isDuplicateVersionError =
errors.length > 0 &&
errors.every(
@@ -175,6 +175,44 @@ describe('AscApiUtils', () => {
});
describe('createBuildUploadAsync', () => {
it.each(['single', 'aggregate', 'mixed', 'other-pointer'])(
'handles only invalid app relationships (%s)',
async kind => {
const relationshipError = new AscApiRequestError('Invalid relationship', 409, {
code: 'ENTITY_ERROR.RELATIONSHIP.INVALID',
source: {
pointer:
kind === 'other-pointer'
? '/data/relationships/build/data/id'
: '/data/relationships/app/data/id',
},
});
const original =
kind === 'aggregate'
? new AggregateError([relationshipError, relationshipError])
: kind === 'mixed'
? new AggregateError([relationshipError, new Error('other')])
: relationshipError;
const client = { postAsync: jest.fn().mockRejectedValue(original) };
const result = AscApiUtils.createBuildUploadAsync({
client,
appleAppIdentifier: '1234567890',
bundleShortVersion: '1.2.3',
bundleVersion: '42',
platform: 'IOS',
});
if (kind === 'mixed' || kind === 'other-pointer') {
await expect(result).rejects.toBe(original);
} else {
await expect(result).rejects.toMatchObject({
errorCode: 'EAS_UPLOAD_TO_ASC_INVALID_APP_RELATIONSHIP',
cause: original,
docsUrl: 'https://expo.fyi/asc-app-id',
});
}
}
);
it.each([false, true])('explains duplicate versions (aggregate: %s)', async aggregate => {
const payload = {
errors: [