mastra-ai/mastra · error · Error

MainSidebarNavLink requires a valid React element child when

Error message

MainSidebarNavLink requires a valid React element child when `asChild` is true so it can apply `SlottedNavChildProps` and merge `itemClassName`.

What it means

When asChild is true, MainSidebarNavLink clones its single React element child to inject className (and SlottedNavChildProps like isActive/data-state). If the child is not a valid React element (text, string, fragment, undefined), cloning is impossible, so the component throws with an explanatory message.

Source

Thrown at packages/playground-ui/src/ds/components/MainSidebar/main-sidebar-nav-link.tsx:127

  children,
  link,
  state,
  Link,
  className,
}: {
  render?: React.ReactElement<SlottedNavChildProps>;
  asChild: boolean;
  children?: React.ReactNode;
  link?: NavLink;
  state: SidebarState;
  Link: LinkComponent;
  className: string;
}) {
  if (render) return React.cloneElement(render, { className: cn(className, render.props.className) });

  if (asChild) {
    if (!React.isValidElement<SlottedNavChildProps>(children)) {
      throw new Error(
        'MainSidebarNavLink requires a valid React element child when `asChild` is true so it can apply `SlottedNavChildProps` and merge `itemClassName`.',
      );
    }

    return React.cloneElement(children, { className: cn(className, children.props.className) });
  }

  if (!link) return children;

  const externalParams = /^(https?:)?\/\//.test(link.url) ? { target: '_blank', rel: 'noreferrer' } : {};

  return (
    <Link href={link.url} {...externalParams} className={className}>
      {link.icon}
      <MainSidebarNavLabel state={state}>{link.name}</MainSidebarNavLabel>
      {children}
    </Link>
  );

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the child of the asChild link is exactly one valid React element (e.g. <Link/>, <a/>).
  2. Move conditionals outside: {cond ? <MainSidebarNavLink asChild><Link/></MainSidebarNavLink> : null}.
  3. Unwrap fragments — pass the inner element directly.
  4. If you only need text, drop asChild and let the component render its default anchor.

Example fix

// before
<MainSidebarNavLink asChild href="/x">{isActive && <Link to="/x">X</Link>}</MainSidebarNavLink>
// after
{isActive && (
  <MainSidebarNavLink asChild href="/x"><Link to="/x">X</Link></MainSidebarNavLink>
)}
Defensive patterns

Strategy: validation

Validate before calling

const child = props.children;
if (!React.isValidElement(child)) {
  // render without asChild or fix the child before enabling slotted props
  return <MainSidebarNavLink href="/x">{child}</MainSidebarNavLink>;
}

Type guard

function isValidSlottedChild(
  c: React.ReactNode,
): c is React.ReactElement<SlottedNavChildProps> {
  return React.isValidElement<SlottedNavChildProps>(c);
}

Try / catch

try {
  return <MainSidebarNavLink asChild href="/x">{child}</MainSidebarNavLink>;
} catch {
  return <MainSidebarNavLink href="/x">{child}</MainSidebarNavLink>; // degrade gracefully
}

Prevention

When it happens

Trigger: Passing asChild with children that are: a plain string ('Home'), a fragment (<>...</>), a conditional expression evaluating to undefined, or multiple children — anything React.isValidElement rejects.

Common situations: Conditional children like {cond && <Link/>} that resolve to false/undefined; passing translated text nodes; wrapping the child in a Fragment 'just to be safe'; refactoring to asChild from a regular-children usage without ensuring a single element.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/92c436c244e15ae4. Report an issue: GitHub.