Skip to content

Accept zero payloads when decoding a Void input#152

Open
k3zi wants to merge 1 commit into
apple:mainfrom
k3zi:void-input-zero-payloads
Open

Accept zero payloads when decoding a Void input#152
k3zi wants to merge 1 commit into
apple:mainfrom
k3zi:void-input-zero-payloads

Conversation

@k3zi

@k3zi k3zi commented Jun 27, 2026

Copy link
Copy Markdown
Member

Motivation

The Swift SDK encodes a Void input as a single empty payload, whereas the other SDKs send zero payloads for no input. In one place, UpdateWithStart, the Swift SDK does the right thing and sends zero payloads. But on decode the worker rejects zero payloads for Void.self: convertPayloads(as: Void.self) requires exactly one. So a Void update sent via UpdateWithStart is rejected before acceptance, and the client sees notFound even though the workflow runs fine.

Making the encode consistently send zero payloads would break older workers that still expect the payload, so it is left as a separate change.

Modifications

In PayloadConverter.convertPayloads, treat a single Void as carrying no payload and ignore the input payload count, matching the other SDKs, which ignore extra input payloads.

Result

A Void update, signal, or query sent with zero payloads is accepted instead of dropped. The encode is unchanged, so it is safe to roll out in any client / worker order.

Other Issues (will file separately)

  • When the input cannot be decoded, the worker rejects the update and the client surfaces notFound, which does not match the other SDKs / APIs that return the conversion failure; the real error is lost.
  • The UpdateWithStart client does not use the update outcome returned in the first ExecuteMultiOperation response; it discards it and makes an extra PollWorkflowExecutionUpdate call. The other SDKs reuse the first response.
  • Encode Void as zero payloads, matching the other SDKs, instead of a single empty payload. This is a breaking wire change because older workers require the payload, so it needs its own change and a version bump.

Test Plan

updateWithStartVoidInput and updateWithStartVoidInputZeroPayloads in WorkflowUpdateTests.swift; swift test passes.

@k3zi
k3zi force-pushed the void-input-zero-payloads branch from 3cd2553 to 3f136ad Compare June 27, 2026 03:38
The Swift SDK encodes a `Void` input as a single empty payload, whereas the other SDKs send zero payloads for no input. In one place, `UpdateWithStart`, the Swift SDK does the right thing and sends zero payloads. But on decode the worker rejects zero payloads for `Void.self`: `convertPayloads(as: Void.self)` requires exactly one. So a `Void` update sent via `UpdateWithStart` is rejected before acceptance, and the client sees `notFound` even though the workflow runs fine.

Making the encode consistently send zero payloads would break older workers that still expect the payload, so it is left as a separate change.

In `PayloadConverter.convertPayloads`, treat a single `Void` as carrying no payload and ignore the input payload count, matching the other SDKs, which ignore extra input payloads.
@k3zi
k3zi force-pushed the void-input-zero-payloads branch from 3f136ad to 50c6540 Compare June 27, 2026 04:25
Comment on lines +74 to +75
// Older Swift clients / workers incorrectly send `Void` input as a JSON payload in certain
// cases; like the other SDKs, ignore extra input payloads for a lone `Void`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you link where the other SDKs are ignoring single payloads? Also do I understand this correct that in the current SDK this is not a problem but when decoding workflows started by older SDKs?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

They aren't ignoring single payloads per-se. They ignore any extra payloads delivered beyond what they are decoding for and only error when not enough were delivered.

In addition we are incorrectly encoding Void as a payload, when it is sent as zero payloads by other SDKs. I.e. Void / () is overloaded in Swift to mean the absence of a type, so it should be encoded as zero payloads, but we encode it as a single zero-byte payload.

.NET - WorkflowInstance.cs

It is intentional that we discard extra input arguments that the signature doesn't accept.

Ruby - workflow_instance.rb

We want to discard extra arguments if we can.

The change in this PR only fixes the Void sent as empty / zero-byte payload case but I can adjust to be general instead if we want to match all SDKs now in that regard. It would be moving towards leniency at least so not so breaking of a change.

@k3zi
k3zi requested a review from FranzBusch July 1, 2026 17:18
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.

2 participants