{"record":{"id":"cbbaf4564274de3f","repo":"moeru-ai/airi","slug":"kit-kitid-is-not-available-for-runtime-run","errorCode":null,"errorMessage":"Kit `${kitId}` is not available for runtime `${runtime}`.","messagePattern":"Kit `(.+?)` is not available for runtime `(.+?)`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugin-sdk/src/plugin-host/core.ts","lineNumber":596,"sourceCode":"  }\n\n  private getModuleOrThrow(moduleId: string) {\n    const module = this.modules.get(moduleId)\n    if (!module) {\n      throw new Error(`Module \\`${moduleId}\\` was not found.`)\n    }\n\n    return module\n  }\n\n  private assertKitAvailableForRuntime(kitId: string, runtime: PluginRuntime) {\n    const kit = this.kits.get(kitId)\n    if (!kit) {\n      throw new Error(`Kit \\`${kitId}\\` is not registered.`)\n    }\n\n    if (!kit.runtimes.includes(runtime)) {\n      throw new Error(`Kit \\`${kitId}\\` is not available for runtime \\`${runtime}\\`.`)\n    }\n\n    return kit\n  }\n\n  listSessions() {\n    return this.extensionSessionService.list()\n  }\n\n  getSession(sessionId: string) {\n    return this.extensionSessionService.get(sessionId)\n  }\n\n  registerKit(kit: KitDescriptor) {\n    return this.kits.register(kit)\n  }\n\n  unregisterKit(kitId: string) {","sourceCodeStart":578,"sourceCodeEnd":614,"githubUrl":"https://github.com/moeru-ai/airi/blob/438a067dde47aa0bdb46c2323d1fe293dc805218/packages/plugin-sdk/src/plugin-host/core.ts#L578-L614","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nhost.registerKit({ kitId: 'widgets', runtimes: ['electron'], capabilities: [...] })\nawait host.start(manifest, { runtime: 'node' }) // announceBinding throws: not available for runtime `node`\n\n// after\nhost.registerKit({ kitId: 'widgets', runtimes: ['electron', 'node'], capabilities: [...] })\nawait host.start(manifest, { runtime: 'node' })","handlingStrategy":"validation","validationCode":"// Before announcing a binding for a session:\nconst runtime = session.runtime ?? 'electron' // mirror host default\nconst available = host.listKits(runtime).some(k => k.kitId === 'my-kit')\nif (!available) {\n  throw new Error(`Kit 'my-kit' does not declare runtime '${runtime}'; widen kit.runtimes or start the session under a supported runtime.`)\n}","typeGuard":"const kitSupportsRuntime = (kit: KitDescriptor, runtime: PluginRuntime): boolean => kit.runtimes.includes(runtime)","tryCatchPattern":"try {\n  host.announceBinding(sessionId, input)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('is not available for runtime')) {\n    // surface a config error: widen kit.runtimes or change session.runtime\n  }\n  throw error\n}","preventionTips":["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."],"tags":["plugin-sdk","kit","runtime","availability"],"backgroundTag":"runtime-mismatch","analyzedSha":"438a067dde47aa0bdb46c2323d1fe293dc805218","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}