Skip to content

Report non-retryable PayloadValidationError as BAD_REQUEST - #3009

Open
bergundy wants to merge 2 commits into
temporalio:mainfrom
bergundy:nexus-payload-validation-bad-request
Open

Report non-retryable PayloadValidationError as BAD_REQUEST#3009
bergundy wants to merge 2 commits into
temporalio:mainfrom
bergundy:nexus-payload-validation-bad-request

Conversation

@bergundy

Copy link
Copy Markdown
Member

What changed

A data converter can now signal that a Nexus operation's input is invalid by throwing a non-retryable ApplicationFailure of type PayloadValidationError while deserializing the input. PayloadSerializer translates such a failure into a BAD_REQUEST HandlerException with the message invalid operation input, retaining the original failure as its cause.

Previously any ApplicationFailure from the data converter propagated and was turned into an INTERNAL handler error by NexusTaskHandlerImpl, which callers retry — so a caller sending invalid input was retried until timeout instead of failing fast.

Unchanged

  • ApplicationFailure of any other type → propagated as before (INTERNAL)
  • A retryable PayloadValidationError → propagated as before (INTERNAL); non-retryable is required
  • HandlerException from the converter → passed through untouched
  • InvalidProtocolBufferException / DataConverterExceptionBAD_REQUEST as before
  • serialize() is untouched — BAD_REQUEST would be wrong for a result-encoding failure

Tests

  • PayloadSerializerTest: positive case asserting BAD_REQUEST, non-retryable, the wrapper message and the preserved cause; negative cases for a different error type and for a retryable PayloadValidationError.
  • OperationInputDeserializationErrorPropagationTest: end-to-end through the test server, including a retryable case that proves the non-retryable guard by being retried.

Cross-SDK

Part of a coordinated change; equivalent PRs exist for Go, TypeScript, Python and .NET. The wrapper message wording is aligned across SDKs, adapted to each SDK's message style.

A data converter can signal that a Nexus operation's input is invalid by
throwing a non-retryable ApplicationFailure of type PayloadValidationError while
deserializing the input. Such a failure is now translated into a BAD_REQUEST
HandlerException retaining the original failure as its cause, instead of the
INTERNAL handler error any other application failure produces.

Application failures of any other type, and retryable PayloadValidationError
failures, keep their existing behavior.
@bergundy
bergundy requested a review from a team as a code owner August 14, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant