{"record":{"id":"514f3a676f03ca8d","repo":"paperclipai/paperclip","slug":"chat-sdk-endpoint-runtime-was-retired","errorCode":null,"errorMessage":"Chat SDK endpoint runtime was retired","messagePattern":"Chat SDK endpoint runtime was retired","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":2274,"sourceCode":"  async initialize(): Promise<void> {\n    await this.initializeChat();\n    this.assertNotRetired();\n    if (this.provider === \"discord\" && this.discordGatewayEnabled) {\n      this.startDiscordGateway();\n    }\n  }\n\n  private async initializeChat(): Promise<void> {\n    this.assertNotRetired();\n    // The service still chooses when to initialize, after installing callback\n    // context. Retirement owns the settlement of that exact SDK operation.\n    this.initialization ??= this.chat.initialize();\n    await this.initialization;\n    this.assertNotRetired();\n  }\n\n  private assertNotRetired(): void {\n    if (this.retired) throw new Error(\"Chat SDK endpoint runtime was retired\");\n  }\n\n  private startDiscordGateway(): void {\n    this.assertNotRetired();\n    if (this.discordGatewayTask) return;\n    const adapter = this.adapter as DiscordAdapter;\n    if (typeof adapter.startGatewayListener !== \"function\") return;\n    const abort = new AbortController();\n    this.discordGatewayAbort = abort;\n    this.discordGatewayTask = (async () => {\n      let rapidRestartCount = 0;\n      while (!abort.signal.aborted) {\n        const sessionStartedAt = Date.now();\n        let listener: Promise<unknown> | null = null;\n        try {\n          await adapter.startGatewayListener(\n            {\n              waitUntil: (task) => {","sourceCodeStart":2256,"sourceCodeEnd":2292,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L2256-L2292","documentation":"The Chat SDK runtime can be retired (shut down) while asynchronous work is still in flight. Every critical entry point calls assertNotRetired(); if the runtime has been retired, this error is thrown to prevent operating on a dead runtime (e.g. initialize() completing after shutdown).","triggerScenarios":"Calling initialize(), startDiscordGateway(), or other guarded methods after the runtime's retire()/shutdown path has set this.retired = true; a pending this.initialization promise resolving after retirement.","commonSituations":"Server shutdown or company teardown racing with an in-flight initialize; Discord gateway restart attempted after retirement; a request arriving during hot adapter reload/replacement; tests tearing down the runtime while a promise is still pending.","solutions":["Check runtime lifecycle: do not call initialize/start methods after retire(); gate calls behind a readiness check.","Serialize shutdown: await all in-flight initialization before retiring.","Recreate a new runtime instance if the endpoint is needed again after retirement.","In tests, await runtime disposal before ending the test to avoid post-teardown calls."],"exampleFix":"// before\nawait oldRuntime.initialize(); // may throw after retire()\n// after\nif (!oldRuntime.isRetired()) {\n  await oldRuntime.initialize();\n} else {\n  runtime = createRuntime(config); // fresh instance\n}","handlingStrategy":"try-catch","validationCode":"if (runtime.isRetired?.()) throw new Error(\"runtime already retired; create a new one\");","typeGuard":"null","tryCatchPattern":"try {\n  await runtime.initialize();\n} catch (err) {\n  if (/was retired/.test(String(err?.message))) {\n    runtime = createRuntime(config); // recreate after shutdown\n    await runtime.initialize();\n  } else throw err;\n}","preventionTips":["Track runtime lifecycle state in callers; never call into a retired runtime.","Await in-flight work before retire() to avoid shutdown races.","Serialize initialize and retire calls (mutex/queue).","In tests, always await teardown before assertions that touch the runtime."],"tags":["lifecycle","shutdown","race-condition"],"backgroundTag":"invalid-state-transition","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}