moeru-ai/airi · error · Error
Extension entrypoint is required for runtime
Error message
Extension entrypoint is required for runtime `${runtime}`. Define one of `entrypoints.<runtime>`, `entrypoints.default`, or `entrypoints.electron` in the extension manifest. What it means
Thrown by FileSystemLoader.resolveEntrypointFor when the manifest's entrypoints map has no entry for the requested runtime, no default, and no electron fallback. Resolution order is entrypoints[runtime] ?? entrypoints.default ?? entrypoints.electron, where runtime defaults to 'electron' when ExtensionLoadOptions.runtime is omitted — so all three keys being absent is a manifest contract violation.
Solutions
- Add a runtime-agnostic entry to the manifest: "entrypoints": { "default": "./dist/index.js" }.
- Or add the specific key for the runtime you load with: "entrypoints": { "node": "./dist/index.node.js" }.
- Pass options.runtime explicitly to loadExtensionFor/host.start so it matches a key that exists in the manifest.
- Validate manifests at scaffolding time (e.g. a check that entrypoints.default or the target runtime key is present).
Example fix
// before (manifest.json)
{
"id": "my-ext",
"entrypoints": { "web": "./dist/index.js" }
}
// loadExtensionFor(manifest) -> runtime defaults to 'electron', no match -> throws
// after
{
"id": "my-ext",
"entrypoints": { "default": "./dist/index.js", "web": "./dist/index.js" }
} Defensive patterns
Strategy: validation
Validate before calling
// Before loadExtensionFor / host.start:
const runtime = options?.runtime ?? 'electron'
const hasEntrypoint = Boolean(
manifest.entrypoints[runtime]
?? manifest.entrypoints.default
?? manifest.entrypoints.electron,
)
if (!hasEntrypoint) {
throw new Error(`Manifest ${manifest.id} lacks entrypoints for runtime '${runtime}'; add entrypoints.default`)
} Type guard
const hasRunnableEntrypoint = (m: ExtensionManifestV1, runtime: string): boolean => Boolean(m.entrypoints[runtime as keyof typeof m.entrypoints] ?? m.entrypoints.default ?? m.entrypoints.electron)
Prevention
- Always include entrypoints.default in generated manifests as the safety net.
- Validate manifests with a schema check at install/scaffold time, including the entrypoints keys.
- Pass options.runtime explicitly so resolution does not silently fall back to 'electron'.
When it happens
Trigger: Manifest with entrypoints: {} or a single entry under a different key (e.g. entrypoints.web) while loading with the default 'electron' runtime; loading under runtime: 'node' when only entrypoints.electron is defined; typo'd runtime key like 'Node'; manifest generated by scaffolding that skipped the entrypoints section.
Common situations: Writing manifests by hand for a new extension; running the same manifest under a new runtime without adding per-runtime entries; build tools that prune 'unused' manifest fields; migrating manifests where the runtime name changed casing.
Related errors
- Extension entrypoint id
- Extension entrypoint is required for runtime \
- Extension \` \` does not support runtime \` \`.
- Failed to resolve extension module. The entrypoint must…
- Cannot declare permissions for unknown plugin
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/f26c91fc1563c721.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugin-sdk/src/plugin-host/runtimes/node/loaders/fs.ts:62
export class FileSystemLoader {
/**
* Resolve a manifest entrypoint for the requested runtime.
*
* Resolution order:
* 1) `entrypoints.<runtime>`
* 2) `entrypoints.default`
* 3) `entrypoints.electron` (legacy fallback for current local extension manifests)
*/
resolveEntrypointFor(manifest: ExtensionManifestV1, options?: ExtensionLoadOptions) {
const runtime = options?.runtime ?? 'electron'
const root = options?.cwd ?? cwd()
const entrypoint
= manifest.entrypoints[runtime]
?? manifest.entrypoints.default
?? manifest.entrypoints.electron
if (!entrypoint) {
throw new Error(''
+ `Extension entrypoint is required for runtime \`${runtime}\`. `
+ 'Define one of `entrypoints.<runtime>`, `entrypoints.default`, '
+ 'or `entrypoints.electron` in the extension manifest.',
)
}
return isAbsolute(entrypoint) ? entrypoint : join(root, entrypoint)
}
async loadExtensionFor(manifest: ExtensionManifestV1, options?: ExtensionLoadOptions) {
const entrypoint = this.resolveEntrypointFor(manifest, options)
const extensionModule = await import(entrypoint)
return coerceExtensionFromModule(extensionModule)
}
}
View on GitHub (pinned to 677329427f)