Published on

Fixing YUP Conditional Validation: 'Branch is Not a Function' Error

Authors
  • Name
    Ripal & Zalak
    Twitter

Fixing YUP Conditional Validation: "Branch is Not a Function" Error

When working with the YUP validation library in JavaScript or TypeScript, you might encounter the error:

TypeError: branch is not a function at Condition.fn

This issue commonly arises when using conditional validation with the when method after updating to newer versions of YUP. In this blog post, we’ll explore the root cause and provide practical solutions to fix this error.


🛠 The Problem

Consider the following schema:

const schema = yup.object().shape({
  userRole: yup.string().required('User Role is required'),
  permissions: yup
    .object()
    .shape()
    .when('userRole', {
      is: (role) => role === 'admin',
      then: () =>
        yup.object({
          accessLevel: yup
            .string()
            .oneOf(['full', 'partial'], 'Invalid access level')
            .required('Access level is required'),
        }),
      otherwise: () =>
        yup.object({
          accessLevel: yup.string().oneOf(['none'], "Only 'none' is allowed for non-admins"),
        }),
    }),
})

This code throws the "branch is not a function" error due to changes in YUP's syntax for when conditions. The then and otherwise properties now require a function that returns a schema instead of directly using a schema.


✅ The Solution

Modify your code to wrap the schema inside a function. Here's the corrected schema:

const schema = yup.object().shape({
  userRole: yup.string().required('User Role is required'),
  permissions: yup
    .object()
    .shape()
    .when('userRole', {
      is: (role) => role === 'admin',
      then: () =>
        yup.object({
          accessLevel: yup
            .string()
            .oneOf(['full', 'partial'], 'Invalid access level')
            .required('Access level is required'),
        }),
      otherwise: () =>
        yup.object({
          accessLevel: yup.string().oneOf(['none'], "Only 'none' is allowed for non-admins"),
        }),
    }),
})

Key Change:

  • Replace:
    then: yup.object({ ... })
    
    With:
    then: () => yup.object({ ... })
    

This applies to otherwise conditions as well.


🌟 Common Scenarios and Fixes

1. Basic when Validation

For simple conditional validations, wrap the then schema in a function:

const schema = yup.object().shape({
  isVerified: yup.boolean().required(),
  profile: yup.object().when('isVerified', {
    is: true,
    then: () =>
      yup.object({
        email: yup.string().email('Invalid email').required('Email is required'),
      }),
    otherwise: () =>
      yup.object({
        phone: yup.string().min(10, 'Invalid phone number').required('Phone is required'),
      }),
  }),
})

2. Multi-Field Conditional Validation

When working with multiple fields in the condition:

const schema = yup.object().shape({
  country: yup.string().required('Country is required'),
  address: yup.object().when(['country'], {
    is: (country) => country === 'US',
    then: () =>
      yup.object({
        state: yup.string().required('State is required for US'),
        zipCode: yup.string().matches(/\d{5}/, 'Invalid zip code'),
      }),
    otherwise: () =>
      yup.object({
        province: yup.string().required('Province is required'),
      }),
  }),
})

🤔 FAQs

Q1: Why did this error start occurring?

YUP introduced breaking changes in version 1.x, where the then and otherwise methods now require functions that return schemas. This is more consistent with its functional programming design.

Q2: Can I fix this without upgrading my code?

The easiest fix is to update your code to the new syntax. If you cannot update, consider downgrading to a pre-1.0 version of YUP.

Q3: What if I’m using TypeScript?

Ensure your when conditions and schemas have proper typings. TypeScript compatibility often improves with the updated syntax.