{"record":{"id":"46b847f9a422a871","repo":"moeru-ai/airi","slug":"unknown-extension-session-sessionid","errorCode":null,"errorMessage":"Unknown extension session: ${sessionId}","messagePattern":"Unknown extension session: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugin-sdk/src/plugin-host/core.ts","lineNumber":516,"sourceCode":"    const grant = moduleId\n      ? session.modules.get(moduleId)?.permissions\n      : session.permissions.granted\n\n    if (grant && this.permissions.grantAllows(grant, input.area, input.action, input.key)) {\n      return\n    }\n\n    throw new PermissionDeniedError({\n      area: input.area,\n      action: input.action,\n      key: input.key,\n    })\n  }\n\n  private getExtensionSessionOrThrow(sessionId: string) {\n    const session = this.extensionSessionService.get(sessionId)\n    if (!session) {\n      throw new Error(`Unknown extension session: ${sessionId}`)\n    }\n\n    return session\n  }\n\n  private createInstallContext(): ExtensionHostInstallContext {\n    return {\n      registerKit: kit => this.registerKit(kit),\n      unregisterKit: kitId => this.unregisterKit(kitId),\n      setResourceResolver: (key, resolver) => this.setResourceResolver(key, resolver),\n      setResourceValue: (key, value) => this.setResourceValue(key, value),\n      announceCapability: (key, metadata) => {\n        this.announceCapability(key, metadata)\n      },\n      markCapabilityReady: (key, metadata) => {\n        this.markCapabilityReady(key, metadata)\n      },\n      markCapabilityDegraded: (key, metadata) => {","sourceCodeStart":498,"sourceCodeEnd":534,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/plugin-sdk/src/plugin-host/core.ts#L498-L534","documentation":"Thrown by the private getExtensionSessionOrThrow() when no ExtensionSession exists for the given sessionId. It is the precondition check for host methods that operate on a live session: announceBinding, activateBinding, updateBinding, degradeBinding, withdrawBinding, bindExtensionKitModule. The session may have been stopped, never started, or the id may be wrong.","triggerScenarios":"Calling any session-scoped ExtensionHost binding method (announceBinding, activateBinding, updateBinding, degradeBinding, withdrawBinding, bindExtensionKitModule) with a sessionId that was never started, was already stopped via host.stop(), or is a typo.","commonSituations":"Holding a stale sessionId after the extension was stopped or reloaded (reload creates a new session identity). Passing a sessionId from a different host instance. Race where the session is torn down between obtaining the id and calling a binding method.","solutions":["Use the sessionId returned by host.start() and avoid caching it across stop()/reload() calls.","After host.stop() or reload(), refresh the sessionId from host.getSession() or listSessions() before calling binding methods.","Check host.getSession(sessionId) returns a defined session before invoking binding APIs."],"exampleFix":"// before — using a stale id after stop\nconst session = await host.start(manifest)\nawait host.stop(session.id)\nawait host.announceBinding(session.id, input) // throws Unknown extension session\n\n// after\nconst current = host.getSession(session.id)\nif (!current) throw new Error('Session no longer active')\nawait host.announceBinding(current.id, input)","handlingStrategy":"validation","validationCode":"const session = host.getSession(sessionId)\nif (!session) {\n  throw new Error(`Session '${sessionId}' is not active. Call host.start(manifest) first.`)\n}\nhost.announceBinding(sessionId, input)","typeGuard":"function isSessionActive(host: ExtensionHost, sessionId: string): boolean {\n  return host.getSession(sessionId) !== undefined\n}","tryCatchPattern":"try {\n  return host.announceBinding(sessionId, input)\n} catch (error) {\n  if (error instanceof Error && /Unknown extension session/.test(error.message)) {\n    // session was stopped or never started; refresh the session id\n  } else {\n    throw error\n  }\n}","preventionTips":["Do not cache session ids across stop()/reload() boundaries; reload creates a new identity.","Call host.getSession(id) before any binding operation to confirm liveness.","Serialize teardown and binding operations to avoid races."],"tags":["session","lifecycle","not-found","binding"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}