Skip to main content

Retry & Error Handling

Workflows support configurable retries for failed steps and expose per-step results. Use retryPolicy to make pipelines resilient to transient failures.

retryPolicy Config

retryPolicy?: { maxRetries: number; backoffMs: number }
maxRetries
number
required
Maximum retry attempts per step before marking it as failed.
backoffMs
number
required
Base delay in milliseconds between retries. Uses exponential backoff (backoffMs * 2^attempt).

Example

const workflow = new Workflow<MyState>({
  name: "Resilient Pipeline",
  initialState: {},
  steps: [...],
  retryPolicy: {
    maxRetries: 3,
    backoffMs: 1000,
  },
});
Retries apply when a step throws an error. The step is re-run up to maxRetries times with exponential backoff between attempts.

StepResult Status

Each step produces a StepResult with a status:
interface StepResult {
  stepName: string;
  status: "done" | "error" | "skipped";
  error?: string;
  durationMs: number;
}
StatusMeaning
doneStep completed successfully.
errorStep failed (after retries, if configured).
skippedStep was skipped (e.g., condition was false in ConditionStep).
stepName
string
Name of the step.
status
'done' | 'error' | 'skipped'
Outcome of the step.
error
string
Error message when status is error.
durationMs
number
Time taken for the step in milliseconds.

WorkflowResult

The workflow returns a WorkflowResult containing final state and step results:
interface WorkflowResult<TState> {
  state: TState;
  stepResults: StepResult[];
}
state
TState
Final state after all steps. Includes updates from successful steps; failed steps may leave partial updates.
stepResults
StepResult[]
One entry per step. Use to check which steps succeeded, failed, or were skipped.

Example: Handling Results

const result = await workflow.run();

// Check for failures
const failed = result.stepResults.filter((s) => s.status === "error");
if (failed.length > 0) {
  console.error("Failed steps:", failed.map((s) => s.stepName));
  failed.forEach((s) => console.error(`  ${s.stepName}: ${s.error}`));
}

// Use final state
console.log("Final state:", result.state);

// Inspect timing
result.stepResults.forEach((s) => {
  console.log(`${s.stepName}: ${s.status} (${s.durationMs}ms)`);
});

Full Example with Retry