OrchardCMS/OrchardCore · error · Error

Invalid async component load result

Error message

Invalid async component load result: ${comp}

What it means

Vue 2.7's async component factory (used by Vue.component(name, () => import(...)) / defineAsyncComponent-style loaders in the CommonJS dev build) validates the resolved module after the dynamic import/load: after unwrapping an ES-module default, the result must be an object (component options) or a function (functional component). Anything else (undefined, a string, null wrapper values, wrong export) triggers this Error, with `comp` interpolated into the message.

Solutions

  1. Ensure the dynamically loaded module's default export (or the named export you point at) is a valid component options object or function.
  2. If the module exports the component as a named export, load it explicitly: () => import('./Comp.vue').then(m => m.Comp).
  3. Check bundler/TS interop settings (esModuleInterop, output module format) so comp.__esModule/Module unwrapping works.
  4. Log the loaded module in the loader to inspect its shape before returning it.

Example fix

// before
Vue.component('my-comp', () => import('./myComp')); // module has no default component

// after
Vue.component('my-comp', () =>
  import('./myComp').then(m => m.default || m.MyComp)
);
Defensive patterns

Strategy: type-guard

Validate before calling

function isValidComponent(comp) {
  if (comp && (comp.__esModule || comp[Symbol.toStringTag] === 'Module')) comp = comp.default;
  return comp != null && (typeof comp === 'object' || typeof comp === 'function');
}
// usage before registering: if (!isValidComponent(m)) console.warn('bad async component');

Type guard

function isComponentLike(v) { return v != null && (typeof v === 'object' || typeof v === 'function'); }

Try / catch

Vue.component('x', function () {
  return import('./x.vue')
    .then(function (m) { return m.default || m; })
    .catch(function (err) {
      if (/Invalid async component load result/.test(err.message)) {
        return FallbackComponent;
      }
      throw err;
    });
});

Prevention

When it happens

Trigger: A dynamic import resolves to a module whose default export is missing or not a component: () => import('./x') where x.js has no component default export; exporting a plain value/string instead of a component options object; mismatched module systems (ES module imported from CJS loader without __esModule/Module tag so the wrong shape survives interop).

Common situations: Migrating Vue 2 code that imported a component from a file that also re-exports constants (named vs default confusion); webpack/vite config changes that alter module format; TypeScript files compiled without esModuleInterop so comp.default is not unwrapped.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/0251ce853c4e8925. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Vendor/vue-2.7.16/vue.common.dev.js:3892

                    else {
                        throw err;
                    }
                })
                    .then((comp) => {
                    if (thisRequest !== pendingRequest && pendingRequest) {
                        return pendingRequest;
                    }
                    if (!comp) {
                        warn$2(`Async component loader resolved to undefined. ` +
                            `If you are using retry(), make sure to return its return value.`);
                    }
                    // interop module default
                    if (comp &&
                        (comp.__esModule || comp[Symbol.toStringTag] === 'Module')) {
                        comp = comp.default;
                    }
                    if (comp && !isObject(comp) && !isFunction(comp)) {
                        throw new Error(`Invalid async component load result: ${comp}`);
                    }
                    return comp;
                })));
    };
    return () => {
        const component = load();
        return {
            component,
            delay,
            timeout,
            error: errorComponent,
            loading: loadingComponent
        };
    };
}

function createLifeCycle(hookName) {
    return (fn, target = currentInstance) => {

View on GitHub (pinned to 4306c0717f)