OrchardCMS/OrchardCore · error · Error

Invalid async component load result

Error message

Invalid async component load result: ${comp}

What it means

Vue 2.7's runtime-only CommonJS dev build (vue.runtime.common.dev.js) applies the same check in its async component loader: the value returned by the loader (after ES-module default interop) must be a component object or function; otherwise it throws `Invalid async component load result: ${comp}`. The runtime build has no compiler, so components must arrive as render-function-based options objects/functions.

Solutions

  1. Ensure loaded components are pre-compiled (render functions) or use the full build (vue.common.dev.js with compiler) if you rely on template strings.
  2. Return the component options object/function explicitly: () => import('./c.js').then(m => m.default).
  3. Check the webpack/vite `vue` alias — runtime-only vs compiler-included build mismatch is a common cause.
  4. Log the loader result to verify its shape before it reaches Vue's validation.

Example fix

// before
Vue.component('chart', () => import('./chart')); // chart.js default-exports { template: '<div/>' } with runtime-only build

// after
// Precompile: export default { render(h) { return h('div'); } }
Vue.component('chart', () => import('./chart').then(m => m.default));
Defensive patterns

Strategy: type-guard

Validate before calling

function assertRenderCapable(comp) {
  if (comp && (comp.__esModule || comp[Symbol.toStringTag] === 'Module')) comp = comp.default;
  if (!comp || (typeof comp !== 'object' && typeof comp !== 'function')) {
    throw new Error('Async loader must resolve to component object/function');
  }
  return comp;
}
// usage: Vue.component('chart', () => import('./chart').then(assertRenderCapable));

Type guard

function hasRenderFn(c) { return c != null && typeof c === 'object' && typeof c.render === 'function'; }

Try / catch

Vue.component('chart', () =>
  import('./chart')
    .then(m => m.default)
    .catch(err => {
      if (/Invalid async component load result/.test(String(err.message))) {
        return { render: h => h('div', 'component failed to load') };
      }
      throw err;
    })
);

Prevention

When it happens

Trigger: Async loader () => import('./c') where the module's default export is a string template or options lacking a render function in the runtime-only build; module resolved to a non-component export; CJS/ESM interop not applied so the raw namespace or wrong value is checked.

Common situations: Using the runtime-only build while components are defined with `template` strings resolved through loaders that return raw strings; mixed Vue 2.7 standalone (with compiler) and runtime builds in one app; webpack alias pointing vue to the runtime build unexpectedly.

Related errors


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

Appendix: source

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

                    else {
                        throw err;
                    }
                })
                    .then((comp) => {
                    if (thisRequest !== pendingRequest && pendingRequest) {
                        return pendingRequest;
                    }
                    if (!comp) {
                        warn(`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)