From cb8c08a40b9ada8b61ee29f3a8b9555cf82db31a Mon Sep 17 00:00:00 2001 From: Satish11012007 Date: Mon, 16 Feb 2026 11:16:03 +0530 Subject: [PATCH 1/3] fix(generate): preserve underlying error when validating registry URL --- PR_DESCRIPTION.md | 28 ++++++++++++++++++++++ src/utils/generate/registry.ts | 12 ++++++++-- test/unit/registry.test.ts | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 PR_DESCRIPTION.md create mode 100644 test/unit/registry.test.ts diff --git a/PR_DESCRIPTION.md b/PR_DESCRIPTION.md new file mode 100644 index 000000000..0be4dfaa6 --- /dev/null +++ b/PR_DESCRIPTION.md @@ -0,0 +1,28 @@ +Title: fix: preserve underlying error when validating registry URL + +Summary + +The `registryValidation` function in `src/utils/generate/registry.ts` previously caught all errors during registry URL validation and rethrew a generic Error that discarded the original error details. This made troubleshooting impossible for users because the underlying cause (DNS resolution, network timeout, TLS/SSL, proxy issues, etc.) was lost. + +What I changed + +- Capture the original error in the catch block and include its message in the thrown error text (`Caused by: ...`). +- Attach the original error to the thrown Error's `cause` property when possible so callers can inspect it programmatically. + +Why + +Preserving the original error helps users and maintainers diagnose registry connection issues more effectively. + +Testing + +- Ran `npm ci` and executed the CLI test suite (`npm run cli:test`). The repository has many test suites; I ran the CLI tests locally to validate behavior. The change is small and focused; adding a dedicated unit test for `registryValidation` is straightforward and I can add it if you'd like. + +Notes + +- I avoided changing the public API; callers still receive an Error but with helpful details and `error.cause` populated when available. + +Suggested PR body for GitHub + +This PR fixes #2013 — preserve the underlying error when validating `--registry-url` so users can see the root cause of failures (DNS, network, SSL, proxy, etc.). + +Would you like me to create the GitHub PR automatically using the GitHub CLI (`gh`) or open a draft PR URL for you? \ No newline at end of file diff --git a/src/utils/generate/registry.ts b/src/utils/generate/registry.ts index 16fdda2e5..90b714d43 100644 --- a/src/utils/generate/registry.ts +++ b/src/utils/generate/registry.ts @@ -13,7 +13,15 @@ export async function registryValidation(registryUrl?: string, registryAuth?: st 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 (err) { + const causeMsg = err instanceof Error ? err.message : String(err); + const errToThrow = new Error(`Can't fetch registryURL: ${registryUrl}\nCaused by: ${causeMsg}`); + try { + // prefer using the standardized `cause` when available + (errToThrow as any).cause = err; + } catch (_) { + // ignore if we can't attach cause + } + throw errToThrow; } } diff --git a/test/unit/registry.test.ts b/test/unit/registry.test.ts new file mode 100644 index 000000000..4580afbe1 --- /dev/null +++ b/test/unit/registry.test.ts @@ -0,0 +1,43 @@ +import { expect } from 'chai'; +import { registryValidation } from '../../src/utils/generate/registry'; + +describe('registryValidation', () => { + const originalFetch = (globalThis as any).fetch; + + afterEach(() => { + (globalThis as any).fetch = originalFetch; + }); + + it('returns undefined when no url provided', async () => { + const result = await registryValidation(undefined); + expect(result).to.equal(undefined); + }).timeout(5000); + + it('wraps fetch errors and preserves cause', async () => { + const networkError = new Error('getaddrinfo ENOTFOUND my-registry.example.com'); + (globalThis as any).fetch = () => { throw networkError; }; + + try { + await registryValidation('https://my-registry.example.com'); + throw new Error('Expected registryValidation to throw'); + } catch (err: any) { + expect(String(err.message)).to.contain("Can't fetch registryURL: https://my-registry.example.com"); + expect(String(err.message)).to.contain('Caused by: getaddrinfo ENOTFOUND my-registry.example.com'); + expect((err as any).cause).to.equal(networkError); + } + }).timeout(5000); + + it('wraps 401 auth response and preserves cause message', async () => { + (globalThis as any).fetch = async () => ({ status: 401 }); + + try { + await registryValidation('https://my-registry.example.com'); + throw new Error('Expected registryValidation to throw'); + } catch (err: any) { + expect(String(err.message)).to.contain("Can't fetch registryURL: https://my-registry.example.com"); + expect(String(err.message)).to.contain('Caused by: You Need to pass either registryAuth'); + expect((err as any).cause).to.be.instanceOf(Error); + expect((err as any).cause.message).to.contain('You Need to pass either registryAuth'); + } + }).timeout(5000); +}); From c9b1df0de3f8ef5c30293fec1ea20fe63583d1c8 Mon Sep 17 00:00:00 2001 From: Satish11012007 Date: Mon, 16 Feb 2026 11:26:18 +0530 Subject: [PATCH 2/3] chore(changelog): note registry validation fix --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c323ebf..e0d20e6ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ - 7580cee: Removal of postman -> asyncapi conversion functionality +### Patch Changes + +- cb8c08a: fix(generate): preserve underlying error when validating registry URL + - Preserve the original error message and attach it as `cause` when registry URL validation fails to improve diagnosability for DNS/network/SSL/proxy failures. Adds unit tests covering the behavior. + ## ⚠ BREAKING CHANGES Remove postman conversion utilities due to unmaintained dependencies and compatibility issues. From 1d8e998235f3203a899cb23a62bfa830b8b782bb Mon Sep 17 00:00:00 2001 From: Satish11012007 Date: Mon, 16 Feb 2026 11:31:40 +0530 Subject: [PATCH 3/3] fix(generate): use typed ErrorOptions for Error.cause to satisfy SonarCloud --- src/utils/generate/registry.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/utils/generate/registry.ts b/src/utils/generate/registry.ts index 90b714d43..367b21ebc 100644 --- a/src/utils/generate/registry.ts +++ b/src/utils/generate/registry.ts @@ -15,13 +15,9 @@ export async function registryValidation(registryUrl?: string, registryAuth?: st } } catch (err) { const causeMsg = err instanceof Error ? err.message : String(err); - const errToThrow = new Error(`Can't fetch registryURL: ${registryUrl}\nCaused by: ${causeMsg}`); - try { - // prefer using the standardized `cause` when available - (errToThrow as any).cause = err; - } catch (_) { - // ignore if we can't attach cause - } - throw errToThrow; + // Use a typed options object to avoid `any`/casts and remain Sonar-friendly. + type LocalErrorOptions = { cause?: unknown }; + const opts: LocalErrorOptions = { cause: err instanceof Error ? err : undefined }; + throw new Error(`Can't fetch registryURL: ${registryUrl}\nCaused by: ${causeMsg}`, opts as ErrorOptions); } }