facebook/react · warning

copyWithRename() expects paths of the same length

Error message

copyWithRename() expects paths of the same length

What it means

copyWithRename is the immutable clone helper behind the DevTools override APIs overrideHookStateRenamePath (ReactFiberReconciler.js:766) and overridePropsRenamePath (ReactFiberReconciler.js:813). It validates that oldPath and newPath have identical length, because it only renames the deepest key of a fixed path. On mismatch it warns and returns undefined - which the caller then assigns to hook.memoizedState/baseState or fiber.pendingProps, silently wiping that state or props to undefined.

Source

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

      // $FlowFixMe[incompatible-use] number or string is fine here
      updated[oldKey] = copyWithRenameImpl(
        // $FlowFixMe[incompatible-use] number or string is fine here
        obj[oldKey],
        oldPath,
        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,

View on GitHub (pinned to eafeac097b)

Solutions

  1. Pass paths of the same length: rename only the deepest key, e.g. ['user','name'] to ['user','username']
  2. Fix the tool's path builder so both arrays come from the same selected node
  3. For a move between depths, use delete then set (overrideHookStateDeletePath followed by overrideHookState) instead of rename

Example fix

// before: lengths differ (1 vs 2) - warns, state becomes undefined
overridePropsRenamePath(fiber, ['user'], ['profile', 'name']);

// after: same depth, only deepest key renamed
overridePropsRenamePath(fiber, ['user', 'name'], ['user', 'username']);
Defensive patterns

Strategy: type-guard

Validate before calling

// validate before calling the DevTools override
if (!isValidRenamePath(oldPath, newPath)) {
  throw new Error('rename requires equal-length paths');
}
overrideHookStateRenamePath(fiber, id, oldPath, newPath);

Type guard

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

Prevention

When it happens

Trigger: Calling overrideHookStateRenamePath(fiber, id, ['user'], ['profile','name']) or overridePropsRenamePath(fiber, ['a'], ['a','b']) - any rename where the two path arrays differ in length. Only reachable from DevTools-style tooling or tests that drive the DevTools hook, never from normal rendering.

Common situations: Custom DevTools forks or inspector UIs that build the two path arrays from different tree states (one captured before expanding a node, one after); test harnesses simulating inline state editing; tools that allow renaming a key while also moving it between depths.

Related errors


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