fix: treat empty entity operation input as no input#283
Open
YunchuWang wants to merge 1 commit into
Open
Conversation
The entity executor parsed operation input with an inline
`inputValue ? JSON.parse(inputValue.getValue()) : undefined` guard. A
protobuf StringValue is always a truthy object, so an empty StringValue
wrapping "" passed the guard and reached JSON.parse(""), which throws
"SyntaxError: Unexpected end of JSON input". The operation then failed
and rolled back instead of running with no input.
Use the shared parseJsonField() helper (already used by the orchestration
and activity executors), which returns undefined for a null/empty
StringValue and wraps genuine parse errors with context via `cause`.
Adds regression tests covering empty-wrapper input, verifying the
operation is dispatched with no input, and confirming a genuine
empty-string JSON value ('""') is still delivered as "".
Fixes #238
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes entity operation input parsing in the worker’s entity executor so that an empty protobuf StringValue is treated as “no input” (rather than attempting JSON.parse("") and failing the operation/rolling back state). This aligns entity execution with the existing protobuf JSON parsing utilities already used elsewhere in the SDK.
Changes:
- Switch entity operation input parsing from inline
JSON.parse(...)to the sharedparseJsonField(...)helper (treats empty wrapper as undefined and improves parse error context). - Add regression tests covering: empty wrapper input succeeds, dispatch receives “no input”, and explicit JSON empty-string (
'""') is preserved.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/durabletask-js/src/worker/entity-executor.ts | Use parseJsonField for operation input so empty StringValue doesn’t crash/rollback. |
| packages/durabletask-js/test/entity-executor.spec.ts | Add targeted regression tests for empty-wrapper vs explicit empty-string JSON input. |
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.
Summary
Fixes a bug in the entity executor where an entity operation whose input is an empty
StringValuecrashes withSyntaxError: Unexpected end of JSON inputand is rolled back, instead of being executed with no input.Why this fix is needed
TaskEntityShim.executeOperation()parsed the operation input like this:The
inputValue ?guard is meant to handle the "no input" case, but it only guards againstundefined. A protobufStringValueis always a truthy object — even when it wraps an empty string. So when a sidecar/scheduler (or another language SDK) sends an operation whose input field is an emptyStringValue(getValue() === ""), the guard passes and the code callsJSON.parse(""), which throws:The
try/catchinexecuteOperation()then converts that into an operation failure and rolls back the state/actions for that operation. The caller receives a confusingSyntaxErrorfor what should have been a successful, no-input operation.This is also inconsistent with the rest of the codebase:
parseJsonField()helper inutils/pb-helper.util.ts.getSerializedState()already guards against empty strings — only the operation-input path did not.Impact
StringValuefor the input field; cross-SDK interop where another language SDK produces empty input wrappers; any protobuf construction that sets an emptyStringValueinstead of omitting the field entirely.The fix
Replace the inline
JSON.parsewith the sharedparseJsonField()helper:parseJsonField():undefinedfor anull/undefinedor emptyStringValue— so an empty wrapper is treated as "no input".cause(invalid JSON still fails, as before, just with a clearer message).Because
parseJsonField()returnsundefinedfor an empty wrapper,operation.hasInputbecomesfalseand the entity method is dispatched with no argument — matching the intended "no input" semantics.Tests
Added a new
empty operation inputsuite toentity-executor.spec.ts:StringValueinput no longer throwsSyntaxError— the operation now succeeds (regression test for the reported bug);hasInput === false);'""') is still delivered to the operation as""— guarding against over-eagerly dropping legitimate empty-string input.Validation
npm run build:core— compiles cleanly.eslinton the changed files — clean.Fixes #238