SWIRLS_
Workflows

Failure policies

Control what happens when a node fails using the optional failurePolicy field, and how the platform retries transient errors.

What it is. What happens when a step fails: fail the run, skip the step, or substitute a fallback value and continue.

Use it when an optional enrichment step should never sink the run, or a safe default beats failing.

Works with every node type; failurePolicy is an optional field on any node.

By default, when a node fails, the entire workflow execution fails. A failurePolicy on that node changes this: the run can skip the node or substitute a fallback value and continue.

failurePolicy is optional and can be set on any node.

How retries work

The platform retries transient failures automatically. Every node runs under a fixed retry policy: 3 attempts for standard nodes, 5 attempts for agent nodes. Errors caused by the workflow definition itself (bad code, an invalid schema, a misconfigured node) are never retried; they would fail the same way every time.

You do not tune this. maxRetries and backoffMs are accepted by the parser but do not change the retry schedule today; the platform's fixed policy governs.

Shape

failurePolicy: {
  strategy: "fail" | "retry" | "skip" | "fallback"
  maxRetries: <number>      // parsed; the fixed platform policy governs
  backoffMs: <number>       // parsed; the fixed platform policy governs
  fallbackValue: <any>      // used with "fallback"
}

Strategies

StrategyBehavior
failNode failure errors the entire execution. This is the default when no policy is set.
retryTransient failures are retried on the platform's fixed schedule. If the node still fails after the last attempt, the execution errors. Errors in your own code or configuration are not retried.
skipMark the node as skipped and continue. Downstream nodes that read context.nodes.<name>.output will see undefined.
fallbackReplace the node's output with fallbackValue and continue as if the node succeeded.

skip and fallback are applied as declared, after the platform's retries are exhausted.

When to use each strategy

fallback is the right choice when the node's output is optional. An enrichment step that sometimes fails should not block the rest of the workflow. Provide a fallback value that downstream nodes can handle gracefully.

skip is the right choice when the node's output is truly optional and downstream nodes can run without it. Skipped nodes produce undefined output, so downstream nodes must handle that case.

fail (the default) is the right choice when there is no safe way to continue without the node's output. Transient failures are still retried before the run fails.

retry makes the default retry-then-fail behavior explicit in the definition. It reads well on nodes that call flaky external services, but it does not add attempts beyond the fixed policy.

Examples

A flaky HTTP endpoint

node fetch_data {
  type: http
  label: "Fetch from API"
  url: @ts { return "https://api.example.com/data" }
  failurePolicy: {
    strategy: "retry"
  }
}

Transient failures (timeouts, rate limits, 5xx responses) are retried on the platform's fixed schedule. If the last attempt still fails, the execution errors.

Fallback on an AI enrichment node

node classify {
  type: ai
  label: "Classify intent"
  kind: object
  model: "anthropic/claude-3.5-sonnet"
  prompt: @ts {
    return "Classify this message: " + context.nodes.root.input.message
  }
  schema: @json {
    {
      "type": "object",
      "required": ["intent"],
      "properties": { "intent": { "type": "string" } }
    }
  }
  failurePolicy: {
    strategy: "fallback"
    fallbackValue: { intent: "unknown" }
  }
}

If the AI call fails (model unavailable, timeout, or invalid response), the node outputs { intent: "unknown" } and the execution continues. Downstream nodes always have a valid intent to work with.

Skip an optional enrichment step

node enrich {
  type: scrape
  label: "Enrich from web"
  url: @ts { return "https://example.com/" + context.nodes.root.output.slug }
  failurePolicy: {
    strategy: "skip"
  }
}

If the web scrape fails, the enrich node is marked as skipped. Any downstream node that reads context.nodes.enrich.output receives undefined. The execution continues to completion.

Downstream behavior after skip or fallback

Nodes downstream of a skipped or fallback node still execute. They receive output from context.nodes.<name>.output:

  • After skip: the output is undefined. Use optional chaining (?.) in @ts blocks that read skipped node output.
  • After fallback: the output is the fallbackValue you specified.

Both cases flow through the normal edge workflow. There is no branching on failure; you handle the difference in downstream node code.

node format_result {
  type: code
  label: "Format result"
  code: @ts {
    const intent = context.nodes.classify.output?.intent ?? "unknown"
    return { formatted: "Intent: " + intent }
  }
}

Further reading

On this page