moeru-ai/airi · error · Error
Failed to resolve extension module. The entrypoint must expo
Error message
Failed to resolve extension module. The entrypoint must export defineExtension(...).
What it means
Thrown by coerceExtensionFromModule() when the imported entrypoint module is neither itself a valid Extension (object with string `id` and function `setup`) nor has a `default` export that is. The loader expects a defineExtension(...) result either as the namespace or as the default export.
Source
Thrown at packages/plugin-sdk/src/plugin-host/runtimes/node/loaders/fs.ts:28
&& 'id' in value
&& typeof (value as { id?: unknown }).id === 'string'
&& 'setup' in value
&& typeof (value as { setup?: unknown }).setup === 'function'
}
function coerceExtensionFromModule(moduleValue: unknown): Extension {
if (isExtensionDefinition(moduleValue)) {
return moduleValue
}
if (typeof moduleValue === 'object' && moduleValue !== null) {
const defaultExport = (moduleValue as { default?: unknown }).default
if (isExtensionDefinition(defaultExport)) {
return defaultExport
}
}
throw new Error('Failed to resolve extension module. The entrypoint must export defineExtension(...).')
}
/**
* Loads extension entrypoints from the local filesystem for the current runtime.
*
* Use when:
* - The host needs to resolve a manifest entrypoint path
* - The host needs to import a `defineExtension(...)` export
*
* Expects:
* - Entry points are valid importable module paths for the active runtime
*
* Returns:
* - Filesystem-backed helpers for resolving and loading extension entrypoints
*/
export class FileSystemLoader {
/**
* Resolve a manifest entrypoint for the requested runtime.View on GitHub (pinned to 27111382b4)
Solutions
- Ensure the entrypoint's default export is the result of defineExtension({ id, setup }): `export default defineExtension({ id, setup })`.
- Confirm the entrypoint file resolved by resolveEntrypointFor is the intended extension file, not a barrel/utility module.
- Verify the entrypoint exports an object with a string `id` and a function `setup` (the isExtensionDefinition contract).
Example fix
// before — extension.ts
import { defineExtension } from '@proj-airi/plugin-sdk'
const ext = defineExtension({ id: 'my-ext', setup(ctx) { /* ... */ } }) // not exported
// after
export default defineExtension({ id: 'my-ext', setup(ctx) { /* ... */ } }) Defensive patterns
Strategy: type-guard
Validate before calling
const mod = await import(entrypoint)
const candidate = mod.default ?? mod
if (typeof candidate !== 'object' || candidate === null
|| typeof candidate.id !== 'string'
|| typeof candidate.setup !== 'function') {
throw new Error(`Entrypoint '${entrypoint}' does not export a defineExtension(...) result`)
} Type guard
function isExtensionDefinition(value: unknown): value is Extension {
return typeof value === 'object'
&& value !== null
&& 'id' in value
&& typeof (value as { id?: unknown }).id === 'string'
&& 'setup' in value
&& typeof (value as { setup?: unknown }).setup === 'function'
} Try / catch
try {
const extension = await loader.loadExtensionFor(manifest, options)
} catch (error) {
if (error instanceof Error && /Failed to resolve extension module/.test(error.message)) {
// entrypoint does not export defineExtension(...); fix the entrypoint exports
} else {
throw error
}
} Prevention
- Always `export default defineExtension({ id, setup })` from the entrypoint file.
- Do not rely on named exports; the loader checks the namespace and its `default` only.
- Add a smoke test that imports the entrypoint and asserts the default export has string id + function setup.
When it happens
Trigger: The entrypoint file resolved by resolveEntrypointFor imports successfully but does not export defineExtension(...) output correctly — e.g. it exports a plain object, a function, or forgets `export default`. Also triggered if defineExtension is called but the result is not exported (just invoked for side effects).
Common situations: Entrypoint file is empty or a stub. Author wrote `defineExtension({ id, setup })` without `export default`. The file exports the extension under a named export (e.g. `export const ext = ...`) instead of default. The resolved path points at the wrong file (e.g. an index that re-exports utilities).
Related errors
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/5d63c5f20a62b5db.
Report an issue: GitHub.