Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
28 changes: 28 additions & 0 deletions PR_DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -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?
8 changes: 6 additions & 2 deletions src/utils/generate/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ 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);
// 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);
}
}
43 changes: 43 additions & 0 deletions test/unit/registry.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});