moeru-ai/airi · error · Error
Extension entrypoint id `${extension.id}` must match manifes
Error message
Extension entrypoint id `${extension.id}` must match manifest id `${options.manifest.id}`. What it means
Thrown by ExtensionHost.startExtension() when the id on the loaded Extension object (from defineExtension) does not equal the id declared in the ExtensionManifestV1 passed to start/startExtension. The host treats the manifest id as the canonical package identity and refuses to start a mismatched entrypoint to prevent impersonation and stale-binding bugs.
Source
Thrown at packages/plugin-sdk/src/plugin-host/core.ts:240
constructor(options: ExtensionHostOptions = {}) {
this.loader = new FileSystemLoader()
this.runtime = options.runtime ?? 'electron'
this.permissionResolver = options.permissionResolver
this.resources.setValue(protocolListProvidersEventName, [] as Array<{ name: string }>)
this.markCapabilityReady(protocolListProvidersEventName, { source: 'plugin-host' })
this.installContext = this.createInstallContext()
for (const contribution of options.contributions ?? []) {
this.installContribution(contribution)
}
}
async startExtension(
extension: Extension,
options: { manifest: ExtensionManifestV1, cwd?: string, runtime?: PluginRuntime },
) {
if (extension.id !== options.manifest.id) {
throw new Error(`Extension entrypoint id \`${extension.id}\` must match manifest id \`${options.manifest.id}\`.`)
}
const sessionIdentity = this.extensionSessionService.nextSessionIdentity()
const extensionIdentity = {
id: extension.id,
version: extension.version,
sessionId: sessionIdentity.sessionId,
}
const persistedGrant = this.persistedPermissionGrants.get(extension.id)
const resolvedGrant = await this.permissionResolver?.({
identity: extensionIdentity,
manifest: options.manifest,
requested: options.manifest.permissions,
persisted: persistedGrant,
}) ?? options.manifest.permissions
const permissionSnapshot = this.permissions.initialize(sessionIdentity.sessionId, options.manifest.permissions, {
grant: resolvedGrant,
persisted: this.permissionResolver ? undefined : persistedGrant,View on GitHub (pinned to 27111382b4)
Solutions
- Align the id in defineExtension({ id: '...' }) with the `id` field in the extension manifest (manifest.json or equivalent).
- If renaming, update both the manifest id and the entrypoint defineExtension id in the same change.
- Add a lint/test step that asserts manifest.id === entrypoint exported id after loading.
Example fix
// manifest.json
{ "apiVersion": "v1", "kind": "manifest.extension.airi.moeru.ai", "id": "my-ext", ... }
// before — entrypoint mismatch
export default defineExtension({ id: 'old-ext', setup(ctx) { ... } })
// after
export default defineExtension({ id: 'my-ext', setup(ctx) { ... } }) Defensive patterns
Strategy: validation
Validate before calling
const extension = await loader.loadExtensionFor(manifest, options)
if (extension.id !== manifest.id) {
throw new Error(`Entrypoint id '${extension.id}' does not match manifest id '${manifest.id}'. Fix the mismatch before starting.`)
}
await host.startExtension(extension, { manifest }) Type guard
function extensionIdMatchesManifest(extension: Extension, manifest: ExtensionManifestV1): boolean {
return extension.id === manifest.id
} Try / catch
try {
await host.start(manifest)
} catch (error) {
if (error instanceof Error && /must match manifest id/.test(error.message)) {
// align defineExtension id with manifest id, then retry
} else {
throw error
}
} Prevention
- Keep the manifest id and the defineExtension id in sync; treat them as the same canonical identity.
- Add a pre-publish test that loads the entrypoint and asserts its exported id equals the manifest id.
- When renaming an extension, update both sources in one commit.
When it happens
Trigger: Calling host.start(manifest) or host.startExtension(extension, { manifest }) where extension.id (set inside defineExtension({ id })) differs from manifest.id. Typically the entrypoint file was edited but the manifest was not, or two extensions share a single entrypoint with different ids.
Common situations: Renaming an extension: the manifest id was updated but the defineExtension call still uses the old id (or vice versa). Copying an extension folder and forgetting to change one of the two ids. Build tooling that generates the manifest from a different source than the entrypoint.
Related errors
- Extension manifest not found: ${extensionId}
- Extension module `${input.id}` is already registered for ses
- Extension entrypoint is required for runtime `${runtime}`. D
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/399feea9f0949b4f.
Report an issue: GitHub.