facebook/react · warning

copyWithRename() expects paths to be the same except for the

Error message

copyWithRename() expects paths to be the same except for the deepest key

What it means

Second validation in copyWithRename (ReactFiberReconciler.js:671): after lengths match, every path segment except the last must be identical, because the helper renames exactly one key in place. If any ancestor segment differs (['address','street'] vs ['addr','street']) it warns and returns undefined, and the DevTools caller then assigns undefined over hook state or pendingProps.

Source

Thrown at packages/react-reconciler/src/ReactFiberReconciler.js:671

        newPath,
        index + 1,
      );
    }
    return updated;
  };

  const copyWithRename = (
    obj: Object | Array<any>,
    oldPath: Array<string | number>,
    newPath: Array<string | number>,
  ): Object | Array<any> => {
    if (oldPath.length !== newPath.length) {
      console.warn('copyWithRename() expects paths of the same length');
      return;
    } else {
      for (let i = 0; i < newPath.length - 1; i++) {
        if (oldPath[i] !== newPath[i]) {
          console.warn(
            'copyWithRename() expects paths to be the same except for the deepest key',
          );
          return;
        }
      }
    }
    return copyWithRenameImpl(obj, oldPath, newPath, 0);
  };

  const copyWithSetImpl = (
    obj: Object | Array<any>,
    path: Array<string | number>,
    index: number,
    value: any,
  ): $FlowFixMe => {
    if (index >= path.length) {
      return value;
    }

View on GitHub (pinned to eafeac097b)

Solutions

  1. Keep all ancestor segments identical and change only the last: ['address','street'] to ['address','streetName']
  2. Recompute newPath from the same node as oldPath in the tool
  3. Use delete + set for cross-branch moves, which rename does not support

Example fix

// before: ancestor segment differs ('address' vs 'addr')
overrideHookStateRenamePath(fiber, id, ['address', 'street'], ['addr', 'street']);

// after: ancestors identical, deepest key renamed
overrideHookStateRenamePath(fiber, id, ['address', 'street'], ['address', 'streetName']);
Defensive patterns

Strategy: type-guard

Validate before calling

const ancestorsEqual = (a, b) =>
  a.length === b.length &&
  a.slice(0, -1).every((k, i) => k === b[i]);

if (!ancestorsEqual(oldPath, newPath)) {
  throw new Error('rename must keep every non-deepest segment identical');
}
overridePropsRenamePath(fiber, oldPath, newPath);

Type guard

function isValidRenamePath(oldPath, newPath) {
  return (
    Array.isArray(oldPath) &&
    Array.isArray(newPath) &&
    oldPath.length === newPath.length &&
    oldPath.every((key, i) => i === oldPath.length - 1 || key === newPath[i])
  );
}

Prevention

When it happens

Trigger: Calling overrideHookStateRenamePath or overridePropsRenamePath with equal-length paths whose non-deepest segments differ, e.g. (['a','b','c'], ['x','b','c']). Emitted once per malformed call from DevTools-like tooling.

Common situations: Inspector code that renames a key in one subtree while the new name is computed from a sibling branch; copy-paste path constants; tree editors that let the user drag a key to a different parent while the rename API assumes the same parent.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/3ca4c37ee16c1066. Report an issue: GitHub.