Repository navigation
fix(testing-sdk): align checkpoint validation with the service - #996
Merged
Merged
Conversation
The local checkpoint server accepted some updates that the service rejects, and rejected others with different messages. So a test could pass locally for a handler that fails in AWS. - Validate Id, ParentId, Name, Type, and Action against the service model, as SubType already was. Messages, their order, and the cap of 10 errors match the service's responses. - Reject an update that changes the Type, SubType, Name, or ParentId of an existing operation. - Apply the service's error and payload size limits. - Accept only START for CALLBACK and CHAINED_INVOKE. - Require WaitOptions and ChainedInvokeOptions on START. - Use the service's error messages, with HTTP status 400. So a failed validation fails the execution, as it does in AWS. Fixes #263
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 13, 2026 22:05 — with
GitHub Actions
Inactive
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 13, 2026 22:28 — with
GitHub Actions
Inactive
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 13, 2026 23:23 — with
GitHub Actions
Inactive
ParidelPooya
had a problem deploying
to
ai-pr-review-runtime
October 13, 2026 23:50 — with
GitHub Actions
Error
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 13, 2026 23:51 — with
GitHub Actions
Inactive
This comment has been minimized.
This comment has been minimized.
The service validates the members of the options structures before any other check. The local server did not. So a CHAINED_INVOKE without a FunctionName passed validation, and failed later in the orchestrator with a plain error instead of an HTTP 400 ValidationException. Validate ChainedInvokeOptions.FunctionName and TenantId, WaitOptions.WaitSeconds, StepOptions.NextAttemptDelaySeconds, and the CallbackOptions timeouts. The messages and their order were recorded from the service.
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 14, 2026 01:46 — with
GitHub Actions
Inactive
This comment has been minimized.
This comment has been minimized.
The service reads the request body before it checks the model. A member of the wrong JSON type fails the request with HTTP 400 SerializationException. The local server ignored such a member. Report the service's SerializationException message for the first member of the wrong type, in the order the SDK writes the body. Read an integer member as the service does: drop the fractional part, and clamp to the 32-bit range. The messages and the coercion were recorded from the service.
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 14, 2026 03:56 — with
GitHub Actions
Inactive
This comment has been minimized.
This comment has been minimized.
yaythomas
reviewed
Oct 14, 2026
The serialization check covered only the members that have model
constraints. So a wrong type in Payload, an Error member, or
ContextOptions.ReplayChildren passed locally, and failed in AWS. For
example, a step that throws { name: "X", message: 1 } produces a
numeric ErrorMessage.
Check the complete OperationUpdate wire schema, including nested
structures and the StackTrace list. Move the check to its own module,
and run it before the model check. Members are read in alphabetical
order of their names, as the service reads them. The messages and the
order were recorded from the service.
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 14, 2026 14:47 — with
GitHub Actions
Inactive
This comment has been minimized.
This comment has been minimized.
yaythomas
reviewed
Oct 14, 2026
The service reads an integer member without its fractional part, and
then applies that integer. The local server validated the integer but
stored the original number. So context.wait({ seconds: 1.5 }) recorded
and scheduled 1.5 seconds locally, and 1 second in AWS.
Store each update with its integer members converted, so local history
and timers use the service's values. A callback timeout of 0 now means
no timeout, as in the service, so a fractional timeout below 1 second
no longer times the callback out at once.
State the whole-value pattern match with an explicit end assertion.
ParidelPooya
temporarily deployed
to
ai-pr-review-runtime
October 14, 2026 19:29 — with
GitHub Actions
Inactive
Codex AI reviewFound one replay-parity issue in the new wire-type handling; boolean coercion is not reflected in stored context state. Reviewed commit |
yaythomas
approved these changes
Oct 14, 2026
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue Link, if available
Fixes #263
Description
The local checkpoint server validates each
CheckpointDurableExecutionrequest. Its checks differed from the service's checks. It accepted some updates that the service rejects. It rejected other updates with different messages. So a test could pass locally for a handler that fails in AWS. This PR makes the local checks match the service.Model checks:
Id,ParentId,Name,Type,ActionSubTypeonly.IdandParentId: 1 to 64 characters from[a-zA-Z0-9-_].Name: 1 to 256 printable ASCII characters,[\x20-\x7E]+.Id,Type, andActionare required.CheckpointDurableExecutionin us-east-1.cafénow fails locally with the sameValidationExceptionas in AWS.The service also checks that
TypeandActionare known enum values. That check is not reproduced. An unknown value still fails, withInvalid operation type.orInvalid action for the given operation type..Metadata consistency
An update for an existing operation must not change its
Type,SubType,Name, orParentId. The service rejects such an update with<Field> value in OperationUpdate is inconsistent with existing operation. Check for non-determinism.. The local server did not check this.Size limits
The local runner invokes the handler synchronously. So the EXECUTION limit is the service's limit for a synchronous invocation. Sizes are UTF-8 bytes.
One consequence affects the oversized-result path:
The oversized-result integration test used a result of 6 MiB + 1000 characters. The service would reject it. The test now uses a result inside the window. A new case asserts that a larger result fails the execution.
Actions and options
START. The service completes them itself. The local server acceptedCANCEL. No SDK code sendsCANCELfor these types.STARTrequiresWaitOptions.STARTrequiresChainedInvokeOptions.The service also rejects a CHAINED_INVOKE to a function in another account or region. Local function names are not ARNs. So that check is not reproduced.
Messages and HTTP status
Cannot start a WAIT that already exists.is nowCannot start a WAIT operation that already exists..InvalidParameterValueExceptionwith HTTP status 400.run()rejected.FAILEDwithCheckpointUnrecoverableExecutionError, as in AWS.Behavior change for users
These checks are stricter. A test that passed only because the local server was more permissive now fails. That test fails in AWS too. A test that matches an old message text must update the text. The CHANGELOG lists each change.
Demo/Screenshots
N/A
Checklist
Testing
Unit Tests
Yes. The validator suites cover each new check and each changed message: model constraints, field order, the 10-error cap, metadata consistency, each payload limit at its boundary, UTF-8 byte counting, and the CALLBACK and CHAINED_INVOKE action sets.
Integration Tests
Yes.
checkpoint-validation.integration.test.tsruns real handlers throughLocalDurableTestRunner. A step name outside printable ASCII, or over 256 characters, fails the execution with the service's message.oversized-execution-result.integration.test.tscovers the EXECUTION payload limit.Results:
@aws/durable-execution-sdk-js-testing: 1234 passed, 3 skipped. Lint passes.@aws/durable-execution-sdk-js-examples(jest and vitest): 267 passed, 3 skipped.@aws/durable-execution-sdk-js-extras: 145 passed.@aws/durable-execution-sdk-js-otel: 457 passed.