From 86c186a6c1b81b7d0c09dbdec781e6e40496332b Mon Sep 17 00:00:00 2001 From: "lijiuyang.5137" Date: Sat, 28 Mar 2026 23:56:04 +0800 Subject: [PATCH] fix: prevent CLI hang when --registry-url points to unreachable host (#2027) Add AbortController with 5-second timeout to the fetch call in registryValidation() so the CLI no longer hangs indefinitely. Switch from GET to HEAD for a lighter validation request, and surface distinct error messages for timeout vs general network failures. Co-Authored-By: Claude Opus 4.6 --- src/utils/generate/registry.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/utils/generate/registry.ts b/src/utils/generate/registry.ts index 16fdda2e5..8d1541528 100644 --- a/src/utils/generate/registry.ts +++ b/src/utils/generate/registry.ts @@ -8,12 +8,26 @@ export function registryURLParser(input?: string) { export async function registryValidation(registryUrl?: string, registryAuth?: string, registryToken?: string) { if (!registryUrl) { return; } + const TIMEOUT_MS = 5000; + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS); try { - const response = await fetch(registryUrl as string); + const response = await fetch(registryUrl as string, { + method: 'HEAD', + signal: controller.signal, + }); if (response.status === 401 && !registryAuth && !registryToken) { throw new Error('You Need to pass either registryAuth in username:password encoded in Base64 or need to pass registryToken'); } - } catch { - throw new Error(`Can't fetch registryURL: ${registryUrl}`); + } catch (error: unknown) { + if (error instanceof Error && error.name === 'AbortError') { + throw new Error(`Registry URL validation timed out after ${TIMEOUT_MS / 1000}s — the host at ${registryUrl} appears unreachable.`); + } + if (error instanceof Error && error.message.startsWith('You Need to pass')) { + throw error; + } + throw new Error(`Unable to reach registry at ${registryUrl}. Ensure the URL is correct and the host is reachable.`); + } finally { + clearTimeout(timeoutId); } }