moeru-ai/airi · error · Error

Kit ` ` is not registered.

Error message

Kit `${kitId}` is not registered.

What it means

Thrown by ExtensionHost.assertKitAvailableForRuntime when a binding announcement (announceBinding / bindExtensionKitModule) references a kitId that is not in the host's kit registry. The host only knows kits that were registered via host.registerKit(...) (or the install context's registerKit) before the plugin tries to bind a module to them. It is a startup/ordering contract: kit contracts must exist before extensions can announce modules against them.

Solutions

  1. Register the kit on the same host instance before starting/announcing: host.registerKit({ kitId: 'my-kit', runtimes: [...], capabilities: [...] }) and only then start the extension or call announceBinding.
  2. Verify the exact kitId string against the registry: const kit = host.getKit('my-kit'); if (!kit) ... — fix typos/casing so KitRef.id and KitDescriptor.kitId match.
  3. Inspect host.listKits() (optionally host.listKits(runtime)) at startup to log which kits are actually registered before extensions run.
  4. If the kit was deliberately unregistered, make sure no in-flight extension session still tries to announce modules for it (stop the session first).

Example fix

// before
const session = await host.start(manifest) // extension setup calls announceBinding('my-kit')
host.registerKit({ kitId: 'my-kit', runtimes: ['node'], capabilities: [] }) // too late

// after
host.registerKit({ kitId: 'my-kit', runtimes: ['node'], capabilities: [] })
const session = await host.start(manifest) // kit already registered when the extension announces
Defensive patterns

Strategy: validation

Validate before calling

// Before announceBinding / starting the extension:
const kit = host.getKit('my-kit')
if (!kit) {
  host.registerKit({ kitId: 'my-kit', runtimes: ['node'], capabilities: [] })
}
// Optionally sanity-check the full registry:
const registered = host.listKits().map(k => k.kitId)
if (!registered.includes('my-kit')) throw new Error(`Register kits first. Have: ${registered.join(', ')}`)

Type guard

const isKitRegistered = (host: ExtensionHost, kitId: string): boolean => host.getKit(kitId) !== undefined

Try / catch

try {
  host.announceBinding(sessionId, { kitId: 'my-kit', moduleId: 'm-1', ... })
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Kit `') && error.message.includes('is not registered.')) {
    // register the kit, then retry the announce once
  }
  throw error
}

Prevention

When it happens

Trigger: Calling host.announceBinding(sessionId, { kitId: 'my-kit', ... }) or the kit-helper path bindExtensionKitModule before host.registerKit({ kitId: 'my-kit', ... }); passing a kitId with a typo or different casing than the registered descriptor; registering the kit asynchronously (e.g. after an await) while the extension setup already announced; the kit was unregistered via unregisterKit during teardown but a late announce still runs.

Common situations: Bootstrapping code that starts an extension before the host finishes registering kit contracts; copy-pasting a KitRef id that drifted from the KitDescriptor kitId; hot-reload/dev flows that re-create the host but keep stale extension code; splitting kit registration into another module that is imported lazily.

Related errors


AI-assisted analysis of moeru-ai/airi@438a067dde (2026-08-18). Data as JSON: /api/errors/98f7f14d10eecfcb. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugin-sdk/src/plugin-host/core.ts:592

    }
    await this.cleanupExtensionSessionModules(session)
    await session.subscriptions.dispose()
    this.extensionSessionService.remove(session.id)
  }

  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) {

View on GitHub (pinned to 438a067dde)