Skip to content

fix(diff): surface parser failures instead of empty ValidationError (fixes #2222)#2223

Open
rokas-reizgys-tg wants to merge 3 commits into
asyncapi:masterfrom
rokas-reizgys-tg:fix/diff-parser-error-empty-message
Open

fix(diff): surface parser failures instead of empty ValidationError (fixes #2222)#2223
rokas-reizgys-tg wants to merge 3 commits into
asyncapi:masterfrom
rokas-reizgys-tg:fix/diff-parser-error-empty-message

Conversation

@rokas-reizgys-tg

Copy link
Copy Markdown

What

asyncapi diff currently exits with code 1 and prints a literal ValidationError: (no diagnostic body) when one of the supplied documents fails to parse. This PR makes the command surface a meaningful, non-empty error message instead.

Why

Two bugs in the parser-failure path combined to swallow the error:

  1. In src/apps/cli/commands/diff.ts, parseDocuments constructed new ValidationError({type: 'invalid-file', err: ...}) for parse failures. 'invalid-file' is the file-not-found template; it renders There is no file or context with name "<path>". and ignores the err: field. The catch block at the bottom of run() already used 'parser-error' correctly, so this was an internal inconsistency.
  2. In src/errors/validation-error.ts, buildError only inspected err.title, err.detail, and err.validationErrors. The current ValidationService.parseDocument returns its error as a plain string ('Failed to parse document'), so none of those checks matched and this.message stayed ''. Even after fix CLI Specification #1, the outer catch in run() wraps the inner ValidationError in another one with type: 'parser-error', and buildError again saw no recognisable fields, so the message remained empty by the time oclif printed it.

See #2222 for full root-cause analysis and reproduction.

How

  • Switch the parseDocuments failure branch from 'invalid-file' to 'parser-error', mirroring the existing pattern in the run() catch block.
  • Add a fallback in buildError so any error shape (string, generic Error, undefined) produces a non-empty message instead of ''. Keeps existing ParserError handling intact when those fields are present.
  • Extract the per-validationError formatting into a small helper to keep buildError's cognitive complexity within the project's lint threshold.

Testing

  • npm test (mocha + c8) - diff integration suite goes from 26 to 27 passing; full suite is consistent with master (the suite has pre-existing flakiness in context/validate tests that's unrelated to this change - reproduces identically on master with no changes).
  • npm run lint - clean (0 warnings, 0 errors).
  • npm run build - clean.

New tests added:

  • test/unit/errors/validation-error.test.ts - covers ValidationError behaviour across all type: branches and the new fallback chain (ParserError shape, plain string, generic Error, undefined, title-only).
  • test/integration/diff.test.ts - asserts that asyncapi diff against specification.yml + specification-invalid.yml surfaces a non-empty ValidationError on stderr (not just ValidationError:).

Manual repro before/after on the existing fixtures:

# before
$ ./bin/run_bin diff test/fixtures/specification.yml test/fixtures/specification-invalid.yml
...
ValidationError:
$ echo $?
1

# after
$ ./bin/run_bin diff test/fixtures/specification.yml test/fixtures/specification-invalid.yml
...
ValidationError: Failed to parse document
$ echo $?
1

Related

Out of scope

A natural follow-up is to propagate the parser's diagnostics array out of ValidationService.parseDocument so users see which validation rules failed (line/column/code) instead of the generic Failed to parse document string. That requires extending ServiceResult and the ValidationError interface, so I left it for a separate PR to keep this one minimal and focused on the empty-message symptom.

…syncapi#2222)

When one of the documents passed to `asyncapi diff` fails to parse, the
command exited with code 1 and printed a literal `ValidationError:`
followed by no diagnostic body, making the failure unactionable for both
humans and CI logs.

Two bugs combined to produce that symptom:

1. `parseDocuments` in `src/apps/cli/commands/diff.ts` constructed a
   `ValidationError` with `type: 'invalid-file'` for parse failures.
   `invalid-file` is the file-not-found template; it renders
   `There is no file or context with name "<path>".` and ignores the
   `err:` field entirely. The catch block in `run()` already used
   `'parser-error'` correctly, so this was an internal inconsistency.
2. `buildError` in `src/errors/validation-error.ts` only inspected
   `err.title`, `err.detail`, and `err.validationErrors`. The current
   `ValidationService.parseDocument` returns the error as a plain
   string (`'Failed to parse document'`), so none of those checks
   matched and `this.message` stayed `''`. Even after fix asyncapi#1, the outer
   `catch` in `run()` wraps the inner `ValidationError` again, and
   `buildError` once more sees no recognisable fields, so the message
   was still empty by the time oclif printed it.

This change:
- Switches the `parseDocuments` failure branch to `'parser-error'` so
  the `err:` field is honoured and the catch wrap behaves consistently.
- Adds a fallback in `buildError` so any error shape (string, generic
  `Error`, or `undefined`) produces a non-empty message instead of `''`.
- Extracts the ParserError-shape walking into a helper to keep
  cognitive complexity within the project's lint threshold.

Tests:
- New unit test covering `ValidationError` behaviour for ParserError,
  string, generic `Error`, undefined, and other-typed inputs.
- New integration test asserting `asyncapi diff` against a valid +
  parse-failing document pair surfaces a non-empty `ValidationError`
  on stderr.

Fixes asyncapi#2222
@changeset-bot

changeset-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d39bb7f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@asyncapi/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To Triage

Development

Successfully merging this pull request may close these issues.

[BUG] asyncapi diff prints empty ValidationError: on parse failure CLI Specification

1 participant