Rensei docs

Validation

Validate a workflow before saving, publishing, or importing it.

Validation runs whenever a workflow is saved or published, converting the canvas graph into a validated WorkflowDefinition before anything is persisted or deployed. Understanding the pipeline helps you debug surprising publish failures.

Validate an unsaved file from the CLI

Use the selected project's catalog to check a local workflow file:

rensei --org acme --project operations workflow validate workflow.yaml
rensei --org acme --project operations workflow validate canvas.json --json

The command requires authentication and access to the selected project. It sends the file to the platform for validation without saving, publishing, or executing the workflow. An invalid result exits with a nonzero code; --json prints structured diagnostics even when validation fails.

The file extension selects the format: .yaml and .yml use workflow YAML; .json uses canvas JSON. For another extension, pass --format workflow-yaml or --format canvas. Both the UTF-8 input and the encoded request are limited to 1 MiB.

Diagnostics include a code, severity, phase, field path, message, and any available line, column, or remediation. The result also lists checked and skipped phases. A valid result establishes only the checked phases. Inspect skipped phases before publishing; validation does not establish recipient readiness or execution admission.

Preview an unsaved graph

Use workflow preview to inspect the same local file as a graph before saving:

rensei --org acme --project operations workflow preview workflow.yaml
rensei --org acme --project operations workflow preview canvas.json --json
rensei --org acme --project operations workflow preview workflow.yaml --svg > workflow.svg

The default output summarizes the graph and findings. --json includes the full preview, compiler diagnostics, pane schemas, and an SVG schematic. --svg writes only the standalone image to standard output; the shell redirection in the example creates the local file. The image is a schematic, so it does not reproduce every custom editor panel.

To inspect a nested group, repeat --scope with its group IDs from outermost to innermost:

rensei --org acme --project operations workflow preview workflow.yaml --scope planning --scope review --svg > review.svg

Preview uses the selected project's catalog and access permissions. Unresolved nodes and external connections are marked explicitly. Invalid content or an unavailable preview exits nonzero after printing available evidence. A preview does not save, publish, or run a workflow, and it does not establish execution readiness. Responses are limited to 3 MiB; use a smaller graph when the preview reports a size limit.

Validation pipeline

1. canvasToDefinitionV2

Converts the canvas graph (React Flow nodes and edges) into the WorkflowDefinition v2 format. This is where the gate handle → branch serialisation happens - see the footgun section below.

2. validateWorkflowFull

Runs the full Zod v3 schema against the definition, plus cross-resource invariants:

  • All step IDs are unique
  • All branches values point at existing step IDs
  • Trigger nodes exist and have valid outputSchema
  • Group definitions pass scope-isolation checks
  • metadata.stateMachine (when present) passes validateStateMachine
  • spec.lifecycle (when present) passes validateLifecycleConfig

3. Connection validation

validateAllConnections checks every edge against the typed port system:

  • Source port type is compatible with target port type
  • No edges cross group scope boundaries without going through interface ports
  • Required input ports have at least one incoming edge

4. Struct type resolution

ValidationContext resolves kind: 'struct' port references to their workspace struct definitions. An unresolved struct ID (e.g. a deleted struct type) is a hard error.

Gate handle → branch footgun

This is the most common cause of gate nodes silently routing to the wrong step after save/reload.

Gate nodes (gate.human_query) have three output handles: approved, rejected, and timeout. These handles only route correctly when canvasToDefinitionV2 serialises them as step.branches - not as step.next.

Correct (canvas serialised with canvasToDefinitionV2):

steps:
  - id: approval-gate
    type: gate
    name: "Approve PR"
    config: { nodeId: gate.human_query, ... }
    branches:
      approved: deploy-step
      rejected: notify-rejection
      timeout:  auto-approve-step

Broken (serialised via the old canvasToWorkflowSteps path or hand-authored YAML):

steps:
  - id: approval-gate
    type: gate
    branches: {}    # empty - handles were not serialised
    next: deploy-step

If you see a gate node that always takes the same path regardless of the approval outcome, check the YAML pane. The branches map must have entries for each handle (approved, rejected, timeout). If any key is missing, the executor uses the next fallback or skips the step entirely.

Fix: Re-save the workflow from the canvas editor. The canvasToDefinitionV2 path runs on every save and will regenerate the correct branches map from the current canvas edges.

Validation result shape

The validator returns a ValidationResult with a structured issues array:

interface ValidationResult {
  valid: boolean
  issues: Array<{
    path: string        // dot-path into the definition, e.g. "steps[2].branches.approved"
    message: string
    severity: "error" | "warning"
  }>
}

Warnings do not block publish. Errors do.

Common errors and fixes

YAML import validation

When you import a workflow from YAML or JSON (POST /api/workflows/{id}/import), the same validation pipeline runs before any changes are applied to the canvas. Import fails atomically - the canvas is not modified if the imported definition is invalid.

Cross-resource invariants

Beyond the structural checks, validateWorkflowFull also enforces workspace-level invariants:

  • Foundational node refs (agent-definition, model-provider, capacity-provider, etc.) must point at existing rows for the workspace
  • credential-provider refs must be connected integrations
  • Subscription projects must belong to the workspace

These are surfaced as validation issues with a path like steps[0].config.agentDefinitionId.

On this page