@@ -5,6 +5,22 @@ import {getCachedCommandInfo, setCachedCommandTomlPreference} from '../local-sto
55import { CreateAppOptions , DeveloperPlatformClient } from '../../utilities/developer-platform-client.js'
66import { AppConfigurationFileName } from '../../models/app/loader.js'
77import { BugError } from '@shopify/cli-kit/node/error'
8+ import { outputInfo , outputDebug } from '@shopify/cli-kit/node/output'
9+
10+ const MAX_PROMPT_RETRIES = 2
11+
12+ const TRY_MESSAGE = [
13+ 'This may happen if:' ,
14+ ' • Running in an unstable environment (container restart, resource limits)' ,
15+ ' • Network interruption during app fetching' ,
16+ '' ,
17+ 'Try running the command again. If the issue persists:' ,
18+ ' • Check system resources and stability' ,
19+ ' • Try running outside of containers/WSL if applicable' ,
20+ ' • Report this issue with the error details and a verbose log' ,
21+ ]
22+ . filter ( Boolean )
23+ . join ( '\n' )
824
925/**
1026 * Select an app from env, list or create a new one:
@@ -30,25 +46,61 @@ export async function selectOrCreateApp(
3046 const name = await appNamePrompt ( options . name )
3147 return developerPlatformClient . createApp ( org , { ...options , name} )
3248 } else {
33- const app = await selectAppPrompt ( searchForAppsByNameFactory ( developerPlatformClient , org . id ) , apps , hasMorePages , {
34- directory : options . directory ,
35- } )
49+ // Capture app selection context
50+ const cachedData = getCachedCommandInfo ( )
51+ const tomls = ( cachedData ?. tomls as { [ key : string ] : AppConfigurationFileName } ) ?? { }
52+
53+ for ( let attempt = 0 ; attempt < MAX_PROMPT_RETRIES ; attempt ++ ) {
54+ try {
55+ // eslint-disable-next-line no-await-in-loop
56+ const app = await selectAppPrompt (
57+ searchForAppsByNameFactory ( developerPlatformClient , org . id ) ,
58+ apps ,
59+ hasMorePages ,
60+ { directory : options . directory } ,
61+ )
62+
63+ const selectedToml = tomls [ app . apiKey ]
64+ if ( selectedToml ) setCachedCommandTomlPreference ( selectedToml )
3665
37- const data = getCachedCommandInfo ( )
38- const tomls = ( data ?. tomls as { [ key : string ] : AppConfigurationFileName } ) ?? { }
39- const selectedToml = tomls [ app . apiKey ]
66+ // eslint-disable-next-line no-await-in-loop
67+ const fullSelectedApp = await developerPlatformClient . appFromIdentifiers ( app . apiKey )
4068
41- if ( selectedToml ) setCachedCommandTomlPreference ( selectedToml )
69+ if ( ! fullSelectedApp ) {
70+ throw new BugError (
71+ `Unable to fetch app ${ app . apiKey } from Shopify` ,
72+ 'Try running `shopify app config link` to connect to an app you have access to.' ,
73+ )
74+ }
4275
43- const fullSelectedApp = await developerPlatformClient . appFromIdentifiers ( app . apiKey )
76+ return fullSelectedApp
77+ } catch ( error ) {
78+ // Don't retry BugError - those indicate actual bugs, not transient issues
79+ if ( error instanceof BugError ) {
80+ throw error
81+ }
4482
45- if ( ! fullSelectedApp ) {
46- // This is unlikely, and a bug. But we still want a nice user facing message plus appropriate context logged.
47- throw new BugError (
48- `Unable to fetch app ${ app . apiKey } from Shopify` ,
49- 'Try running `shopify app config link` to connect to an app you have access to.' ,
50- )
83+ const errorObj = error as Error
84+
85+ // Log each attempt for observability
86+ outputDebug ( `App selection attempt ${ attempt + 1 } /${ MAX_PROMPT_RETRIES } failed: ${ errorObj . message } ` )
87+
88+ // If we have retries left, inform user and retry
89+ if ( attempt < MAX_PROMPT_RETRIES - 1 ) {
90+ outputInfo ( 'App selection failed. Retrying...' )
91+ } else {
92+ throw new BugError ( errorObj . message , TRY_MESSAGE )
93+ }
94+ }
5195 }
52- return fullSelectedApp
96+
97+ // User-facing error message with key diagnostic info
98+ const errorMessage = [
99+ 'Unable to select an app: the selection prompt was interrupted multiple times.' ,
100+ '' ,
101+ `Available apps: ${ apps . length } ` ,
102+ ] . join ( '\n' )
103+
104+ throw new BugError ( errorMessage , TRY_MESSAGE )
53105 }
54106}
0 commit comments