fix: improve error messages for invalid payloads in Zeebe command binding - #4412
Merged
cicoyle merged 9 commits intoJul 10, 2026
Merged
Conversation
…ding When a duration field (timeToLive, timeout, requestTimeout, retryBackOff) received an invalid value, the binding returned a bare "invalid duration" or "time: invalid duration ..." error with no indication of which field failed or what format is expected. Implement UnmarshalJSON on publishMessagePayload, activateJobsPayload, failJobPayload, and createInstancePayload to unmarshal duration fields individually and wrap parse errors with the field name and a format hint (e.g. "invalid value for field 'timeToLive': ...; expected a Go duration string (e.g. \"30s\", \"5m\", \"1h30m\")"). Adds 14 unit tests asserting that error messages include the field name, the offending value, and duration format guidance. All 80 tests pass. Fixes dapr#4093 Signed-off-by: Nelson Parente <nelson@diagrid.io>
nelson-parente
force-pushed
the
fix/zeebe-command-binding-error-messages
branch
from
June 17, 2026 08:11
112192a to
3b9cdf7
Compare
2 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves the Zeebe command binding’s user-facing error messages when JSON payload duration fields contain invalid values by adding per-payload UnmarshalJSON implementations that wrap duration parsing errors with field context, and it adds unit tests to validate the new messages.
Changes:
- Added custom
UnmarshalJSONmethods to Zeebe command payload structs to wrap duration parsing errors with field names and format hints. - Added unit tests covering invalid/valid/null/numeric duration inputs for each affected payload/field.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| bindings/zeebe/command/publish_message.go | Adds custom unmarshal for timeToLive to wrap duration parsing errors with field context. |
| bindings/zeebe/command/publish_message_test.go | Adds tests asserting field-scoped duration error messages and regression coverage for numeric/null inputs. |
| bindings/zeebe/command/fail_job.go | Adds custom unmarshal for retryBackOff to wrap duration parsing errors with field context. |
| bindings/zeebe/command/fail_job_test.go | Adds tests asserting field-scoped duration error messages and regression coverage for numeric/null inputs. |
| bindings/zeebe/command/create_instance.go | Adds custom unmarshal for requestTimeout to wrap duration parsing errors with field context. |
| bindings/zeebe/command/create_instance_test.go | Adds tests asserting field-scoped duration error messages and regression coverage for numeric/null inputs. |
| bindings/zeebe/command/activate_jobs.go | Adds custom unmarshal for timeout and requestTimeout to wrap duration parsing errors with field context. |
| bindings/zeebe/command/activate_jobs_test.go | Adds tests asserting field-scoped duration error messages and regression coverage for numeric/null inputs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…tion errors (Copilot review) Signed-off-by: Nelson Parente <nelson_parente@live.com.pt>
…on errors (Copilot review) Signed-off-by: Nelson Parente <nelson_parente@live.com.pt>
nelson-parente
marked this pull request as ready for review
June 19, 2026 09:36
cicoyle
requested changes
Jul 6, 2026
cicoyle
left a comment
Contributor
There was a problem hiding this comment.
I have 2 comments that could clean things up a little. Otherwise lgtm 👍🏻
I have only 2 comments but the GH UI is showing 3 when submitting my review, there should only be the 2...
Address the two review comments on the shadow-struct pattern: - Use a local type alias in each UnmarshalJSON so the shadow struct only re-declares the raw duration fields instead of hand-mirroring every field of the payload. - Extract the repeated duration-decode logic and its error message into a shared parseOptionalDuration helper (single errInvalidDurationFormat const), removing the message that was duplicated five times. No behavior change: error messages still name the field and offending value; unit tests unchanged and passing. Signed-off-by: Nelson Parente <nelson_parente@live.com.pt>
cicoyle
approved these changes
Jul 10, 2026
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.
Problem
When a duration field in a Zeebe command binding payload contains an invalid value, the error returned is unhelpful. For example, sending
"timeToLive": "PT1M"(ISO-8601 — the format Zeebe itself uses) or"timeToLive": "1minute"produced:or
Neither message tells the user which field failed, what value was rejected, or what format is expected.
Root cause
metadata.Duration.UnmarshalJSON(indapr/kit) returns a bare error fromtime.ParseDurationorerrors.New("invalid duration")for invalid inputs. The Go JSON decoder propagates this error throughjson.Unmarshalwith no field-level context, so callers only see the raw parse error.Affected operations and fields:
publish-messagetimeToLiveactivate-jobstimeout,requestTimeoutfail-jobretryBackOffcreate-instancerequestTimeoutFix
Implemented
UnmarshalJSONon each affected payload struct. Duration fields are decoded individually via a shadow struct usingjson.RawMessage, allowing parse errors to be wrapped with the field name and a format hint.Before:
After:
Tests
Added 14 unit tests (no live broker required) asserting that:
"duration string") is presentAll 80 tests pass (
go test ./bindings/zeebe/...).Fixes #4093
📖 Documentation: dapr/docs#5220