"{{<nodeId>.<field>}}", where <nodeId> is a 24-character step id or the trigger's _id{"nodeId": "<stepId>", "field": "root.email", "defaultValue": "<safe-value>"}"webhook_trigger.email" is not a binding. It is text, and it is what a step writes when the binding is wrong. Do not save one.trigger._id, and a trigger payload field is normally read from root.platformActionFields in GET /catalog, for example Total XP, and reference {{<readStepId>.Total XP}}. A label you send is kept as sent, so the label in your node is the one later steps must use; a community that renamed its XP unit returns a different catalog label for the same key. Neither mistake is refused. A field key that is not one of the community's fields is stored as sent, and a reference to a label the step does not produce is saved too. POST /{workflowId}/validate reports them as the warnings UNKNOWN_USER_FIELD (with the allowed keys) and REFERENCE_UNKNOWN_FIELD, and deploy still proceeds. At run time the step reads or writes nothing: a write step with a mistyped key pays nothing and reports no error. Read the warnings before you deploy.GET /catalog returns platformActionFields.get and platformActionFields.post, each entry carrying the key the step stores, the label the platform stores beside it, and whether the field is builtin or custom.trigger._id (the source for trigger fields) and the _id of the step whose output you want to read. Never copy an id from another workflow: ids are per workflow even when the step names and payloads look identical.POST /{workflowId}/validate and in the deploy response, the write and the deploy both succeed, and the reference resolves to nothing at run time. Read the warnings before you deploy:field is read from the source step's result. The value of field is the step id itself, meaning "the whole result"; anything else is a path into it.{{nodeId.path}} template becomes path on the source step's result. A template whose first part is a 24-hex step id that is not in the workflow is reported as the warning REFERENCE_UNRESOLVABLE, and a run leaves it as literal text. A {{...}} whose first part is not an id at all, such as {{amount}}, is reported as the warning TEMPLATE_NOT_A_REFERENCE, because a run leaves that text as it is and the value never resolves. The id must also sit directly against the dot: {{<id> .path}} is not a reference. A copy is not the case to worry about: duplicate and import rewrite the templates they carry.REFERENCE_UNKNOWN_FIELD; a path that reads a field off a number or a list is REFERENCE_SHAPE_MISMATCH.POST /{workflowId}/validate reports EMPTY_FIELD_LABEL when another step reads it, and the deploy still proceeds, so the reader resolves to nothing at run time.defaultValue is a test value, and the API's dry run does not use it. A dry run resolves a value exactly as a triggered run would, so a missing path stays missing. A live test uses the canvas test resolution, where a default stands in for a missing value, and a live test that pays really writes it. A triggered run never uses a default: it fails the step with Missing workflow mapping: source node ..., field ....triggerPayload does not need a default at all, and a triggered run ignores it.wouldDo.selectUser.value must be the member identifier, not {{...}} text and not root.email.wouldDo.fields[0].value must be the amount, not the field expression.wouldDo.users must contain the member the platform resolved. An empty list means the selector did not resolve.GET /{workflowId}/nodes/{nodeId}: the stored options must show the reference, not the resolved sample. A stored sample that happens to look right is the failure this check exists to catch.| What the dry run shows | Likely cause | Fix |
|---|---|---|
wouldDo.users empty, step failed with User not found | The identity is text, or the field path is wrong for this trigger | Fix the selector's nodeId and field. |
| The written value is the mapping expression | The value slot holds a bare string | Replace it with a template or a reference object. |
REFERENCE_NOT_UPSTREAM from validate | The step reads a step that runs after it, or a sibling branch | Move the step, or read an earlier step. |
REFERENCE_MAY_BE_UNSET warning | The step reads a branch step that may not have run | Accept it, or move the read into the same branch. |
REFERENCE_UNRESOLVED | The id belongs to another workflow | Use this workflow's own step id. |
REFERENCE_UNKNOWN_FIELD | The reference names a label the step does not produce | Use the label on that step's fields[], or the catalog's label for the key. |
REFERENCE_SHAPE_MISMATCH | The reference reads a field off a number or a list | Read the value whole, or read a field of an object result. |
REFERENCE_UNRESOLVABLE | The step id in the reference or template is not in this workflow | Use this workflow's own step id. |
TEMPLATE_NOT_A_REFERENCE warning | A {{...}} whose first part is not a step id, so the run leaves it as text | Reference a step id, or keep the text deliberately. |
| A reference object resolves to nothing | The path is correct but the payload has no such field: a triggered run fails the step with Missing workflow mapping | Fix the sender's payload or the path. A defaultValue does not cover a triggered run. |
| A template resolves to nothing | A {{nodeId.path}} whose path is missing from the payload becomes an empty string, and the run continues with it. A template whose node id is not in the workflow stays as literal text | Validate before deploying: REFERENCE_UNRESOLVABLE reports a template that names no step in the workflow, and REFERENCE_UNKNOWN_FIELD reports a path its step does not produce. Neither is visible at run time. |
node.field string for you. It is text by design; the API does not guess.