moeru-ai/airi · error · Error
Kit ` ` is not available for runtime ` `.
Error message
Kit `${kitId}` is not available for runtime `${runtime}`. What it means
Thrown by assertKitAvailableForRuntime when the kit IS registered but its KitDescriptor.runtimes array does not include the runtime the session is running under. The host resolves the runtime from session.runtime ?? host runtime, so a kit scoped to one runtime (e.g. ['electron']) cannot serve bindings created by a session started in another runtime (e.g. 'node' or 'web'). This enforces per-runtime kit availability declared at registration time.
Solutions
- Add the session's runtime to the kit descriptor: host.registerKit({ kitId: 'k', runtimes: ['electron', 'node'], ... }) so it covers the runtime actually in use.
- Start the extension with the runtime the kit supports: host.start(manifest, { runtime: 'electron' }) instead of running it under an unsupported runtime.
- Confirm which runtime is effective — announceBinding uses session.runtime ?? host runtime, so print session.runtime before binding.
- Use host.listKits(sessionRuntime) to verify the kit appears for that runtime before the extension announces.
Example fix
// before
host.registerKit({ kitId: 'widgets', runtimes: ['electron'], capabilities: [...] })
await host.start(manifest, { runtime: 'node' }) // announceBinding throws: not available for runtime `node`
// after
host.registerKit({ kitId: 'widgets', runtimes: ['electron', 'node'], capabilities: [...] })
await host.start(manifest, { runtime: 'node' }) Defensive patterns
Strategy: validation
Validate before calling
// Before announcing a binding for a session:
const runtime = session.runtime ?? 'electron' // mirror host default
const available = host.listKits(runtime).some(k => k.kitId === 'my-kit')
if (!available) {
throw new Error(`Kit 'my-kit' does not declare runtime '${runtime}'; widen kit.runtimes or start the session under a supported runtime.`)
} Type guard
const kitSupportsRuntime = (kit: KitDescriptor, runtime: PluginRuntime): boolean => kit.runtimes.includes(runtime)
Try / catch
try {
host.announceBinding(sessionId, input)
} catch (error) {
if (error instanceof Error && error.message.includes('is not available for runtime')) {
// surface a config error: widen kit.runtimes or change session.runtime
}
throw error
} Prevention
- Declare kit.runtimes from a shared RUNTIMES constant so adding a new app runtime updates every kit.
- Assert host.listKits(targetRuntime).some(k => k.kitId === id) in dev-mode preflight checks for extensions.
- Log session.runtime at start; do not assume the host default applies when sessions carry their own runtime.
When it happens
Trigger: host.registerKit({ kitId: 'k', runtimes: ['electron'] }) then announceBinding from a session started with runtime: 'node' (session.runtime wins over the host default); bindExtensionKitModule uses this.runtime of a host constructed for 'web' while the kit only lists 'electron'; starting the same extension manifest under a different runtime without widening the kit descriptor.
Common situations: Porting an Electron-scoped kit to the node or web host; declaring runtimes: ['electron'] out of habit then running tests under the node runtime; manifest/session runtime option overriding the expected host runtime; adding a new runtime to the app without updating existing kit descriptors.
Related errors
- Kit ` ` is not registered.
- Cannot declare permissions for unknown plugin
- Cannot grant permissions to unknown plugin
- Electron transport is not available in web runtime.
- Electron transport is not implemented yet.
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-08-18).
Data as JSON: /api/errors/cbbaf4564274de3f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugin-sdk/src/plugin-host/core.ts:596
}
private getModuleOrThrow(moduleId: string) {
const module = this.modules.get(moduleId)
if (!module) {
throw new Error(`Module \`${moduleId}\` was not found.`)
}
return module
}
private assertKitAvailableForRuntime(kitId: string, runtime: PluginRuntime) {
const kit = this.kits.get(kitId)
if (!kit) {
throw new Error(`Kit \`${kitId}\` is not registered.`)
}
if (!kit.runtimes.includes(runtime)) {
throw new Error(`Kit \`${kitId}\` is not available for runtime \`${runtime}\`.`)
}
return kit
}
listSessions() {
return this.extensionSessionService.list()
}
getSession(sessionId: string) {
return this.extensionSessionService.get(sessionId)
}
registerKit(kit: KitDescriptor) {
return this.kits.register(kit)
}
unregisterKit(kitId: string) {View on GitHub (pinned to 438a067dde)