OrchardCMS/OrchardCore · error · Error

Invalid async component load result

Error message

Invalid async component load result: ${comp}

What it means

Same Vue 2.7 async-component validation as the common.dev build, in the ESM browser build (vue.esm.browser.js): after the loader promise resolves and any ES-module default is unwrapped, the resulting value must be an object (options) or function (component). Otherwise the loader throws `Invalid async component load result: ${comp}`.

Solutions

  1. Make the loaded module export the component options object or function as its default export.
  2. Map the specific named export in the loader: () => import('./c.js').then(m => m.MyComponent).
  3. Confirm you're not passing a Vue 3-style component definition to Vue 2.7; adapt it to Vue 2 options API.
  4. Inspect the resolved module (console.log(m)) to see its actual export shape.

Example fix

// before
const AsyncComp = () => import('./widget.js'); // default export is a string template

// after
// widget.js: export default { template: '...', ... }
const AsyncComp = () => import('./widget.js').then(m => m.default);
Defensive patterns

Strategy: type-guard

Validate before calling

function validAsyncComp(loader) {
  return function () {
    return loader().then(function (m) {
      var c = (m && (m.__esModule || m[Symbol.toStringTag] === 'Module')) ? m.default : m;
      if (!(c && (typeof c === 'object' || typeof c === 'function'))) {
        throw new Error('Module did not export a Vue component');
      }
      return c;
    });
  };
}

Type guard

function isVue2Component(v) { return v != null && typeof v === 'object' && ('render' in v || 'template' in v || typeof v === 'function'); }

Try / catch

const AsyncComp = () => import('./widget.js')
  .then(m => {
    const c = m.default || m.Widget;
    if (!c || (typeof c !== 'object' && typeof c !== 'function')) throw new Error('Bad export');
    return c;
  })
  .catch(err => { console.error(err); return FallbackComponent; });

Prevention

When it happens

Trigger: Component factory () => import(...) resolving to a module without a component default export; resolving to a non-component value (string template, plain object of helpers, undefined from a misresolved path); interop failure so the wrapper object isn't unwrapped via __esModule/Symbol.toStringTag.

Common situations: Browser-native ESM builds importing .js component files that export named members only; typo'd import paths resolving to wrong files; mixing Vue 2 and Vue 3 component definitions (Vue 3 defineAsyncComponent/functional shapes rejected here).

Related errors


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

Appendix: source

Thrown at src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Vendor/vue-2.7.16/vue.esm.browser.js:3884

                    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)