You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Native worker poll responses omit the protocol_version body field #1001
Native Server 3.0.5 returns POST /api/worker/workflow-tasks/poll without the protocol_version body field. PHP Server 2.11.8 includes it. The Server reference says worker-plane responses "always echo the server's advertised version in the same header plus the protocol_version body field".
The published CLI checks both, so dw workflow-task:poll fails against native 3.0.5:
{"error":"Server error: invalid worker-protocol response body for [/worker/workflow-tasks/poll]; expected protocol_version same-major compatible with [1.0].","exit_code":1,"command":"workflow-task:poll","namespace":"default"}
Evidence (2026-11-03, lab machine, loopback only)
Same request against both published images: a pending workflow on a fresh task queue, a registered worker, then a poll with X-Durable-Workflow-Protocol-Version: 1.0.
Triage (Server). This is a confirmed defect against the documented contract.
Contract
docs/server-reference.md:911-914: "worker-plane responses always echo the server's advertised version in the same header plus the protocol_version body field."
PHP enforces this centrally. app/Support/WorkerProtocol.php:760-770, WorkerProtocol::json, does $payload['protocol_version'] ??= $version; $payload['server_capabilities'] ??= … on every worker response, so no endpoint can omit it.
Native cause (3.0.5, bc24589d)
The worker middleware (rust/src/runtime/http.rs:691-697) adds only the X-Durable-Workflow-Protocol-Version header to every worker-plane response. Each handler adds the body field itself.
Error paths (admission_error, worker_response, the guard refusals) do add it. The successful workflow-task poll responses don't:
Other worker-plane success bodies may have the same gap. That's why a per-endpoint patch is the wrong shape.
Proposed fix
Mirror PHP's central rule in the worker middleware. For a worker-plane JSON object response, set protocol_version and server_capabilities only when absent (??= semantics), so existing endpoint values are untouched.
Read the body with a bound. Non-JSON and non-object bodies pass through unchanged.
Tests:
a route sweep over every worker-plane endpoint's success, empty and refusal shapes, asserting that body and header agree;
a regression for poll with a task and empty poll;
a counterfactual against 3.0.5's middleware.
Installed check: dw workflow-task:poll 2.3.3 against the fixed image.
Impact
The published SDKs aren't affected. Installed acceptance of PHP, Python and Rust against native passed, and they don't require the body field.
What breaks is the published CLI's raw worker-protocol commands, such as dw workflow-task:poll 2.3.3, which check both the header and the body.
Release: recommendation and decision are with General in chat. The fix is small. 3.1.0 is the natural home, because main now carries 3.1.0 work (#978). A 3.0.6 would need a release branch from bc24589d.
Activity
rmcdaniel commentedon Nov 3, 2026
Triage (Server). This is a confirmed defect against the documented contract.
Contract
docs/server-reference.md:911-914: "worker-plane responses always echo the server's advertised version in the same header plus theprotocol_versionbody field."app/Support/WorkerProtocol.php:760-770,WorkerProtocol::json, does$payload['protocol_version'] ??= $version; $payload['server_capabilities'] ??= …on every worker response, so no endpoint can omit it.Native cause (3.0.5,
bc24589d)rust/src/runtime/http.rs:691-697) adds only theX-Durable-Workflow-Protocol-Versionheader to every worker-plane response. Each handler adds the body field itself.admission_error,worker_response, the guard refusals) do add it. The successful workflow-task poll responses don't:rust/src/runtime/store.rs:2003,{"task", "poll_status": "leased", "server_capabilities"};:2041, the empty poll.Proposed fix
protocol_versionandserver_capabilitiesonly when absent (??=semantics), so existing endpoint values are untouched.dw workflow-task:poll2.3.3 against the fixed image.Impact
dw workflow-task:poll2.3.3, which check both the header and the body.Release: recommendation and decision are with General in chat. The fix is small. 3.1.0 is the natural home, because main now carries 3.1.0 work (#978). A 3.0.6 would need a release branch from
bc24589d.