Skip to content

feat(parser): add errorHandler option for inline parse error handling#5352

Merged
dreamorosi merged 10 commits into
aws-powertools:mainfrom
Zelys-DFKH:feat/parser-error-handler
Jul 9, 2026
Merged

feat(parser): add errorHandler option for inline parse error handling#5352
dreamorosi merged 10 commits into
aws-powertools:mainfrom
Zelys-DFKH:feat/parser-error-handler

Conversation

@Zelys-DFKH

@Zelys-DFKH Zelys-DFKH commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Changes

Adds an optional errorHandler callback to ParserOptions, letting callers intercept parse failures and return a custom response instead of throwing.

The motivation comes from #4191: when @parser is stacked with other decorators that expect a fully-typed event, safeParse: true doesn't compose well -- the outer decorators see ParsedResult rather than the actual payload. An error handler keeps the event type clean while still providing a recovery path on parse failure. Thanks to @codyfrisch for walking through this use case in detail.

The callback receives the ParseError. If it returns a non-undefined value, that becomes the Lambda/Middy response and stops further processing. If it returns undefined, the original error is rethrown -- so you can handle specific failure cases without silently absorbing unexpected ones. Non-ParseError exceptions (e.g., from schema transforms) always propagate as-is.

Both the @parser class decorator and parser() Middy middleware support the new option.

Issue number: closes #4191


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@dreamorosi dreamorosi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Zelys-DFKH, thank you for picking this up and for the well-structured PR - and apologies for the delay in getting to the review.

The direction matches what we discussed in #4191 and the implementation is easy to follow, however there are a few things we need to address before this can move forward - see the inline comments for the details and reasoning:

  • an async errorHandler currently swallows parse failures and lets the handler run with the unparsed event (must fix)
  • in the Middy.js flavor, short-circuiting from before skips every other middleware's after phase - I'd like the recovery to go through the onError phase instead
  • safeParse and errorHandler should be mutually exclusive at the type level
  • the callback should receive the original event alongside the error
  • the Middy.js middleware's response type should reflect the error handler's return type

On top of that:

  • the feature needs documentation in docs/features/parser.md (the safeParse section is the natural home for it) plus code snippets under examples/snippets/parser
  • missing test cases: envelope + errorHandler, non-ParseError propagation, and the safeParse interaction
  • biome check currently fails on formatting in parser.middy.test.ts

Happy to clarify or discuss any of these - thanks again for the contribution!

Comment thread packages/parser/src/middleware/index.ts Outdated
Comment thread packages/parser/src/middleware/index.ts Outdated
Comment thread packages/parser/src/types/parser.ts Outdated
Comment thread packages/parser/src/types/parser.ts Outdated
Comment thread packages/parser/src/middleware/index.ts Outdated
@dreamorosi

Copy link
Copy Markdown
Contributor

btw could you please leave a quick comment on #4191? We'd like to assign the issue to you for tracking, but GitHub only allows assigning users who have either commented on the issue or are collaborators — so right now we can't. Once you've commented, we'll assign it to you. Thanks!

Constrain errorHandler to synchronous returns (type + runtime guard),
move Middy.js recovery into onError so other middlewares' after/onError
phases still run, make safeParse and errorHandler mutually exclusive at
the type level, pass the original event to errorHandler alongside the
error, and thread the handler's return type through MiddlewareObj.

Also fixes two bugs found during self-review after implementing the
above: errorHandler could be invoked for a ParseError unrelated to this
parser's own parse failure (now scoped via a per-request WeakSet in the
middleware and a narrower try/catch in the decorator), and the sync
guard only checked for a native Promise, missing other thenables.

Adds docs, example snippets, and the missing test cases called out in
review.
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XL PRs between 500-999 LOC, often PRs that grown with feedback and removed size/L PRs between 100-499 LOC labels Jul 8, 2026
@Zelys-DFKH

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review, @dreamorosi, and sorry for the slow turnaround. All five points are addressed below, along with the docs, tests, and the biome fix.

  • errorHandler is now constrained to synchronous returns at the type level, with a runtime guard as a backstop. A type test and a runtime test cover the async case.
  • Moved the Middy.js recovery into onError, exactly as you suggested: request.response is set directly (never returned), so the rest of the onError chain still runs. A regression test attaches another middleware's onError and confirms it still fires after parser recovers.
  • safeParse and errorHandler are now mutually exclusive via a discriminated union; the invalid combination fails to compile, covered by a type test.
  • errorHandler now receives (error, event) in both flavors.
  • The Middy MiddlewareObj response type threads through the errorHandler's return type now. Kept the decorator loosely typed per your note.
  • Docs live under the safeParse section in docs/features/parser.md, with snippets for both flavors under examples/snippets/parser.
  • Added the three missing test cases (envelope + errorHandler, non-ParseError propagation, safeParse/errorHandler exclusion), plus a couple more that fell out of the onError change.
  • Fixed the biome formatting failure.

One more thing came up while testing the onError change: since ParseError is public API, both flavors were treating any ParseError reaching them as this parser's own failure, including one a customer's handler might throw for unrelated reasons. Fixed that by scoping recovery to this parser instance's own before-phase failure (a WeakSet keyed on the request for the middleware, a narrower try/catch around just the parse() call for the decorator), with regression tests for both.

Let me know if I've missed anything, or if you'd rather take a different approach on any of these.

Bring in upstream changes to resolve the "behind" mergeable_state on
PR aws-powertools#5352 before it's reviewed further.
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XL PRs between 500-999 LOC, often PRs that grown with feedback and removed size/XL PRs between 500-999 LOC, often PRs that grown with feedback labels Jul 8, 2026
@svozza

svozza commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

There is a SonarQube issue (very simple fix), can you address it?

Addresses SonarQube S6606: the ternary only ever branched on
undefined, so ?? is equivalent and simpler.
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XL PRs between 500-999 LOC, often PRs that grown with feedback and removed size/XL PRs between 500-999 LOC, often PRs that grown with feedback labels Jul 8, 2026
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XL PRs between 500-999 LOC, often PRs that grown with feedback and removed size/XL PRs between 500-999 LOC, often PRs that grown with feedback labels Jul 9, 2026

@dreamorosi dreamorosi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick and thorough turnaround @Zelys-DFKH - all the points from the previous review have been addressed exactly as discussed: the sync-only errorHandler constraint, the onError-based recovery in the Middy.js flavor, the mutually exclusive types, the event in the callback signature, the threaded response type, plus the docs, snippets, and the extra test coverage. We're getting close to merging this.

There's one small inconsistency left, introduced by the SonarQube follow-up - see the inline comment. Once that's sorted I think we're good to go.

Comment thread packages/parser/src/errorHandler.ts Outdated
Restores the documented contract that only undefined triggers a
rethrow. The earlier SonarQube-driven switch to ?? incorrectly
treated null the same as undefined, but null can be a legitimate
value a customer's errorHandler intentionally returns. Adds test
coverage for both flavors.
Leaves a note at the exact spot a future SonarQube pass is likely to
flag again, so the next person doesn't repeat the same regression.
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XL PRs between 500-999 LOC, often PRs that grown with feedback and removed size/XL PRs between 500-999 LOC, often PRs that grown with feedback labels Jul 9, 2026
@powertools-for-aws-oss-automation powertools-for-aws-oss-automation Bot added size/XL PRs between 500-999 LOC, often PRs that grown with feedback and removed size/XL PRs between 500-999 LOC, often PRs that grown with feedback labels Jul 9, 2026
@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

@dreamorosi dreamorosi self-requested a review July 9, 2026 17:45

@dreamorosi dreamorosi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for addressing the review comments and implementing the feature!

@dreamorosi dreamorosi merged commit de752b9 into aws-powertools:main Jul 9, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL PRs between 500-999 LOC, often PRs that grown with feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Injectable error handler for parser

3 participants