Skip to content

# Validation Steps

Validation steps catch invalid input early, before expensive operations run. Structure them to fail fast with no retries.

## Why Explicit Validation Steps?

Section titled “Why Explicit Validation Steps?”

pgflow retries all exceptions based on `maxAttempts`. Without explicit validation, input errors waste retry attempts:

    // Without validation - wastes retry attempts on invalid inputnew Flow<{ email: string }>({ slug: 'sendEmail', maxAttempts: 5 })  .step(    { slug: 'send' },    async (input) => {      if (!input.run.email.includes('@')) {        throw new Error('Invalid email');  // Retries 5 times!      }      return await sendEmail(input.run.email);    }  )

With explicit validation, failures stop immediately:

    // With validation - fails immediately on invalid inputnew Flow<{ email: string }>({ slug: 'sendEmail' })  .step(    { slug: 'validInput', maxAttempts: 1 },    (input) => {      if (!input.run.email.includes('@')) {        throw new Error('Invalid email');      }      return input.run;    }  )  .step(    { slug: 'send', dependsOn: ['validInput'], maxAttempts: 5 },    async (input) => await sendEmail(input.validInput.email)  )

## Keep Validation Synchronous

Section titled “Keep Validation Synchronous”

Validation steps should be fast, synchronous functions that check input format and structure. Avoid async operations like database queries or API calls - those belong in separate steps with appropriate retry configuration.

    // Good: Fast, synchronous validation.step(  { slug: 'validOrder', maxAttempts: 1 },  (input) => {    const { amount, items } = input.run;
        if (amount <= 0) throw new Error('amount must be positive');    if (!items?.length) throw new Error('items cannot be empty');
        return input.run;  })
    // Bad: Async checks in validation.step(  { slug: 'validCustomer', maxAttempts: 1 },  async (input) => {    // Database lookups belong in separate steps with retries    const exists = await checkCustomerExists(input.run.customerId);    if (!exists) throw new Error('Customer not found');    return input.run;  })

Tip

Validation steps check format and structure (email format, positive numbers, array length). Existence checks and external validations belong in regular steps with retry configuration.

## See Also

Section titled “See Also”

- Retrying Steps - Understanding failure types and retry policies
- Context Object - Accessing validated input in dependent steps