facebook/react · error · Error

284

284

Error message

Expected ref to be a function, an object returned by React.createRef(), or undefined/null.

What it means

markRef() validates every ref attached to a fiber before scheduling the Ref effect. React accepts exactly three ref shapes: a function (callback ref), a ref object (from useRef()/React.createRef()), or null/undefined. Any primitive - a string, number, boolean - throws during beginWork, before the element can render.

Source

Thrown at packages/react-reconciler/src/ReactFiberBeginWork.js:1422

    }
  }
  const nextProps: ProfilerProps = workInProgress.pendingProps;
  const nextChildren = nextProps.children;
  reconcileChildren(current, workInProgress, nextChildren, renderLanes);
  return workInProgress.child;
}

function markRef(current: Fiber | null, workInProgress: Fiber) {
  // TODO: Check props.ref instead of fiber.ref when enableRefAsProp is on.
  const ref = workInProgress.ref;
  if (ref === null) {
    if (current !== null && current.ref !== null) {
      // Schedule a Ref effect
      workInProgress.flags |= Ref | RefStatic;
    }
  } else {
    if (typeof ref !== 'function' && typeof ref !== 'object') {
      throw new Error(
        'Expected ref to be a function, an object returned by React.createRef(), or undefined/null.',
      );
    }
    if (current === null || current.ref !== ref) {
      // Schedule a Ref effect
      workInProgress.flags |= Ref | RefStatic;
    }
  }
}

function mountIncompleteFunctionComponent(
  _current: null | Fiber,
  workInProgress: Fiber,
  Component: any,
  nextProps: any,
  renderLanes: Lanes,
) {
  resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress);

View on GitHub (pinned to eafeac097b)

Solutions

  1. Locate the offending element via the error's component stack and inspect its ref value
  2. Replace string or primitive refs with an object ref (useRef/createRef) or a callback ref
  3. If the ref arrives via a spread object, strip the ref key before spreading or set ref to a valid value
  4. Type the prop as React.Ref<T> so the compiler rejects primitives

Example fix

// before
<input ref="username" />;

// after
function Form() {
  const username = useRef(null);
  return <input ref={username} />;
}
Defensive patterns

Strategy: type-guard

Validate before calling

function safeProps(props) {
  if ('ref' in props && !isValidRef(props.ref)) {
    throw new TypeError(`Invalid ref of type ${typeof props.ref}: ${String(props.ref)}`);
  }
  return props;
}

Type guard

function isValidRef(ref) {
  return (
    ref == null ||
    typeof ref === 'function' ||
    (typeof ref === 'object' && 'current' in ref)
  );
}

Try / catch

Render-phase throw: an ErrorBoundary above the element catches it. Log the component stack, then fix the ref value at its source - retrying without the fix re-throws identically.

Prevention

When it happens

Trigger: Passing a legacy string ref (ref="input"); passing a computed value that is a primitive (ref={someString}, ref={0}, ref={true}); spreading a props object that contains a stray ref key; forwarding a non-ref value through React.forwardRef.

Common situations: Codebases migrating off removed string-ref behavior; dynamically built props objects where a ref key leaks in from data; refactors where a callback ref loses its function wrapper; TypeScript code that bypasses ref types with any.

Related errors


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