jquense/yup · error · TypeError

Must include `key` or `index` for nested validations

Error message

Must include `key` or `index` for nested validations

What it means

yup's asNestedTest builds the per-field test for validating an object property or array element. It requires either `key` (object field name) or `index` (array position) so it can read the nested value from the parent and build the correct path. If both are null, yup cannot address the nested value and throws this TypeError instead of producing a bogus path.

Source

Thrown at src/schema.ts:540

        }
        if (--count <= 0) {
          nextOnce(nestedErrors);
        }
      });
    }
  }

  asNestedTest({
    key,
    index,
    parent,
    parentPath,
    originalParent,
    options,
  }: NestedTestConfig): RunTest {
    const k = key ?? index;
    if (k == null) {
      throw TypeError('Must include `key` or `index` for nested validations');
    }

    const isIndex = typeof k === 'number';
    let value = parent[k];

    const testOptions = {
      ...options,
      // Nested validations fields are always strict:
      //    1. parent isn't strict so the casting will also have cast inner values
      //    2. parent is strict in which case the nested values weren't cast either
      strict: true,
      parent,
      value,
      originalValue: originalParent[k],
      // FIXME: tests depend on `index` being passed around deeply,
      //   we should not let the options.key/index bleed through
      key: undefined,
      // index: undefined,

View on GitHub (pinned to ff31eee8a2)

Solutions

  1. Use the public API (object().shape({...}), array().of(...), validateAt(path, value)) so yup supplies key/index itself.
  2. If calling asNestedTest directly, pass either `key: 'fieldName'` or `index: 0` in the config object.
  3. Check custom integrations/plugins that build NestedTestConfig and ensure the field identifier is forwarded from the parent loop.
  4. After a yup upgrade, update internal-API usage to the current asNestedTest signature.

Example fix

// before
schema.asNestedTest({ parent: data, parentPath: 'user', originalParent: data, options });
// after
schema.asNestedTest({ key: 'user', parent: data, parentPath: 'user', originalParent: data, options });
Defensive patterns

Strategy: validation

Validate before calling

// if you must call asNestedTest, verify config first
function callNestedTest(schema, cfg) {
  if (cfg.key == null && cfg.index == null) {
    throw new TypeError('asNestedTest requires key or index');
  }
  return schema.asNestedTest(cfg);
}

Type guard

function hasNestedKey(cfg: { key?: string | number; index?: number }): boolean {
  return cfg.key != null || cfg.index != null;
}

Try / catch

try {
  const test = schema.asNestedTest({ key, index, parent, parentPath, originalParent, options });
  test({ value: parent[key], options }, panic, next);
} catch (e) {
  if (e instanceof TypeError && /key.*index/.test(e.message)) {
    console.error('NestedTestConfig missing key/index:', cfg);
  }
}

Prevention

When it happens

Trigger: Calling low-level schema internals (e.g. schema.asNestedTest({...}) or casting/validating through internals like cast with nested schemas) without passing key/index; usually via misuse of internal APIs or a plugin/binding that composes nested schemas incorrectly rather than through normal object().shape()/array().of() usage.

Common situations: Custom form-library bindings (e.g. hand-rolled Formik alternatives) wiring yup internals; calling validateAt/cast on nested schemas with hand-built options objects; after upgrading yup where the internal NestedTestConfig contract changed.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jquense/yup@ff31eee8a2 (2026-08-31). Data as JSON: /api/errors/468f7ecace051294. Report an issue: GitHub.