ionic-team/ionic-framework · error · Error

animation not registered

Error message

animation not registered

What it means

Thrown by MenuController._createAnimation() when no animation builder is registered for the requested menu `type`. The controller keeps a Map of builders; the built-in 'reveal', 'push', and 'overlay' are registered automatically. Any other type name that has not been registered via menuController.registerAnimation() triggers the throw when the menu tries to open.

Source

Thrown at core/src/utils/menu-controller/index.ts:193

  };

  const _setOpen = async (menu: MenuI, shouldOpen: boolean, animated: boolean, role: string): Promise<boolean> => {
    if (isAnimatingSync()) {
      return false;
    }
    if (shouldOpen) {
      const openedMenu = await getOpen();
      if (openedMenu && menu.el !== openedMenu) {
        await openedMenu.setOpen(false, false);
      }
    }
    return menu._setOpen(shouldOpen, animated, role);
  };

  const _createAnimation = (type: string, menuCmp: MenuI) => {
    const animationBuilder = menuAnimations.get(type) as any; // TODO(FW-2832): type
    if (!animationBuilder) {
      throw new Error('animation not registered');
    }

    const animation = animationBuilder(menuCmp);
    return animation;
  };

  const _getOpenSync = (): HTMLIonMenuElement | undefined => {
    return find((m) => m._isOpen);
  };

  const getMenusSync = (): HTMLIonMenuElement[] => {
    return menus.map((menu) => menu.el);
  };

  const isAnimatingSync = (): boolean => {
    return menus.some((menu) => menu.isAnimating);
  };

View on GitHub (pinned to 625f9c38ad)

Solutions

  1. Use one of the built-in types: 'overlay', 'reveal', or 'push'.
  2. If you need a custom type, call menuController.registerAnimation('myType', myBuilder) before the menu opens (e.g. in app initialization).
  3. Check the spelling and case of the type value against what you registered.
  4. If registering in a lazy bundle, eager-register a fallback or ensure the bundle loads before any menu can open.

Example fix

// before
<ion-menu type="custom-reveal"></ion-menu> <!-- never registered -->

// after
import { menuController } from '@ionic/core';
menuController.registerAnimation('custom-reveal', myRevealBuilder);
// then
<ion-menu type="custom-reveal"></ion-menu>
Defensive patterns

Strategy: validation

Validate before calling

// Built-in types are registered automatically:
const BUILTIN = ['overlay','reveal','push'];
const type = BUILTIN.includes(menuType) ? menuType : 'overlay';
// or, for custom:
menuController.registerAnimation('custom', builder); // before open

Type guard

function isRegisteredMenuType(name: string, registered?: Set<string>): boolean {
  const defaults = ['overlay','reveal','push'];
  return defaults.includes(name) || (registered?.has(name) ?? false);
}

Prevention

When it happens

Trigger: An <ion-menu type="..."> (or config menuType) is set to a custom name that was never registered with menuController.registerAnimation(name, builder), or to a typo like 'Overlay'/'overlays'. The throw fires at open time when the menu calls menuController._createAnimation(this.type, this).

Common situations: Using a custom menu animation without first calling registerAnimation; misspelling a built-in type; setting a global config menuType to a name only registered in a lazy-loaded bundle that hasn't loaded yet; copying a type name from a tutorial that registered a custom animation you didn't include.

Related errors


AI-assisted analysis of ionic-team/ionic-framework@625f9c38ad (2026-08-12). Data as JSON: /api/errors/e3b5ded7c6740b6d. Report an issue: GitHub.