Validation and Errors

Understand when workflow validation runs, how error envelopes are structured, and how to troubleshoot field-level errors.


Every workflow definition is validated before it is persisted. Errors come back with structured field-path data so you can pinpoint exactly which step and which field is wrong.

When validation runs

Two endpoints share the same validation pipeline:

EndpointWhat it does
POST /v1/workflowsValidates the definition, then persists it on success.
POST /v1/workflows/validateValidates the definition only. Never persists.

The validation pipeline

Each definition flows through these stages in order. The first stage to fail returns an error and the rest are skipped.

  1. Parse YAML or JSON. Syntactic well-formedness.
  2. Step count check. At least one step; not more than the configured maximum (12 steps).
  3. CUE schema validation. Top-level keys, step shape, action keys, and per-action parameter types.
  4. Step flattening. The steps array is normalized into a canonical, source-ordered representation.
  5. Variable references. Every ${...} reference resolves to a real input field, a known step output, or a syntactically valid expression, and never to a later step (forward reference).
  6. Expression compilation. Every inline ${expr: ...} and every compute.outputs expression is compiled to surface syntax errors at definition time.

Validation errors are returned as HTTP 400 (most cases) or HTTP 422 (semantic validation failures). They never reach the runtime.

Error envelope

Every error response from the Workflow API uses this shape:

{
  "errors": [
    {
      "code": "invalid_workflow_definition",
      "detail": "Validation failed for workflow definition",
      "details": {
        "step": "1",
        "action_name": "send_money",
        "field": "amount",
        "field_path": "steps[0].send_money.amount",
        "message": "amount must be a numeric centavo string greater than 0"
      }
    }
  ]
}

The errors array can hold more than one entry. The details object is populated for validation errors with structured field-path data so client tooling can point to the exact line in the user's YAML.

Common validation failures

CodeWhat triggered itHow to fix
workflow_no_stepsThe steps array is empty or missing.Add at least one step.
workflow_too_many_stepsThe number of steps exceeds the configured maximum (12 steps).Split the workflow into smaller, chained workflows.
invalid_workflow_definitionA reference targets a step that does not exist, a step has no recognized action key, or a ${...} is malformed.Read the details.field_path to find the offending field.
invalid_workflow_definitionA compute expression fails to compile.Check the expression syntax; expressions follow Go-style operators.
invalid_workflow_definitionA step references a later step (forward reference).Reorder the steps so the producer comes before the consumer.
invalid_workflow_definitionAn amount is set to a non-numeric value, or currency is not PHP.Use a numeric centavo string and currency: "PHP".
invalid_workflow_definitionA provider value is not one of auto, paymongo, instapay, pesonet.Pick a supported provider. See Send Money Step.
invalid_request_bodyThe HTTP body is not valid YAML/JSON, or the wrong Content-Type header was sent.Send text/plain for YAML, application/json for JSON.

Common runtime errors

These appear in the standard envelope when reading instances, submitting events, or triggering work. They are returned by individual operations rather than the validation pipeline.

CodeHTTPWhen it fires
workflow_not_found404The workflow ID is wrong or belongs to the other livemode.
instance_not_found404The instance ID is wrong or belongs to the other livemode.
step_not_waiting422An event was submitted but the addressed wait_event step is not currently waiting.
event_window_expired409The wait state has already timed out or completed.
livemode_mismatch403A request acts on a resource in the opposite livemode (rare; most cross-mode reads 404).
trigger_not_found404The trigger ID is wrong or belongs to the other livemode.

For the full authentication-related codes, see Authentication.