{"record":{"id":"bd222170d08f8fa4","repo":"paperclipai/paperclip","slug":"chat-sdk-runtime-is-shutting-down","errorCode":null,"errorMessage":"Chat SDK runtime is shutting down","messagePattern":"Chat SDK runtime is shutting down","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":3183,"sourceCode":"    if (!previous) return false;\n    this.endpoints.delete(endpointId);\n    this.retiringEndpoints.set(endpointId, previous);\n    await previous.shutdown();\n    this.retiringEndpoints.delete(endpointId);\n    return true;\n  }\n\n  private nextReplacementGeneration(endpointId: string): number {\n    const next = (this.replacementGenerations.get(endpointId) ?? 0) + 1;\n    this.replacementGenerations.set(endpointId, next);\n    return next;\n  }\n\n  private assertReplacementCurrent(\n    endpointId: string,\n    generation: number,\n  ): void {\n    if (this.shuttingDown) throw new Error(\"Chat SDK runtime is shutting down\");\n    if (this.replacementGenerations.get(endpointId) !== generation) {\n      throw new Error(\n        `Chat SDK runtime replacement for endpoint ${endpointId} was superseded`,\n      );\n    }\n  }\n\n  async replaceEndpoint(\n    options: CreateChatSdkEndpointRuntimeOptions,\n  ): Promise<ChatSdkEndpointRuntime> {\n    if (this.shuttingDown) throw new Error(\"Chat SDK runtime is shutting down\");\n    const generation = this.nextReplacementGeneration(options.endpointId);\n    return await this.enqueueLifecycle(options.endpointId, async () => {\n      this.assertReplacementCurrent(options.endpointId, generation);\n      await this.retireEndpoint(options.endpointId);\n      this.assertReplacementCurrent(options.endpointId, generation);\n      const next = createChatSdkEndpointRuntime(options);\n      this.endpoints.set(options.endpointId, next);","sourceCodeStart":3165,"sourceCodeEnd":3201,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L3165-L3201","documentation":"assertReplacementCurrent is the guard applied when installing a replacement chat SDK runtime for an endpoint. If the runtime is shutting down, it throws 'Chat SDK runtime is shutting down'; if the recorded replacement generation for the endpoint no longer matches, it throws the 'was superseded' error. This ensures only the newest replacement wins and none are installed during teardown.","triggerScenarios":"Installing a runtime replacement concurrently with runtime shutdown, or a replacement whose generation counter no longer equals the latest registered generation for that endpointId (an even newer replacement already claimed the slot).","commonSituations":"Service shutdown racing an in-flight endpoint swap; two restart/replacement flows racing for the same endpoint; a restart routine issuing a second generation before the first is installed.","solutions":["Check runtime shutdown state before scheduling a replacement; skip replacements during teardown","Re-read the latest generation for the endpoint and re-issue the replacement if superseded","Serialize replacement installation per endpoint (queue or lock) to avoid generation races","Treat the error as a benign no-op when it occurs during shutdown and let the new runtime take over"],"exampleFix":"// before\nruntime.installReplacement(endpointId, generation);\n// after\nconst latest = runtime.getReplacementGeneration(endpointId);\nif (latest === generation && !runtime.isShuttingDown) {\n  runtime.installReplacement(endpointId, generation);\n}","handlingStrategy":"try-catch","validationCode":"if (runtime.isShuttingDown) return; // skip replacement during teardown","typeGuard":null,"tryCatchPattern":"try { installReplacement(endpointId, generation); } catch (e) { if ((e as Error).message.startsWith('Chat SDK runtime')) { /* benign: superseded or shutting down; skip */ } else throw e; }","preventionTips":["Serialize per-endpoint replacement installation with a lock or queue","Re-read the latest generation before installing and retry once if superseded","Suppress this error as a no-op during process shutdown","Log generation mismatches to detect racing restart routines"],"tags":["lifecycle","race-condition","shutdown","runtime"],"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"}