{"record":{"id":"43863865f8e9621b","repo":"paperclipai/paperclip","slug":"telegram-authenticated-dispatch-contract-is-unavai","errorCode":null,"errorMessage":"Telegram authenticated dispatch contract is unavailable","messagePattern":"Telegram authenticated dispatch contract is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/chat-sdk-runtime.ts","lineNumber":2094,"sourceCode":"      1,\n      Math.min(options.webhookIngressTimeoutMs ?? 2_500, 10_000),\n    );\n    this.adapter = createProviderAdapter(\n      options.providerConfig,\n      options.logger,\n      options.callbacks,\n      options.endpointId,\n      (fatal) => {\n        this.discordGatewayFatal = fatal;\n      },\n    );\n    if (this.provider === \"telegram\") {\n      const adapter = this.adapter as unknown as {\n        botUserId?: string;\n        processUpdate(update: unknown, options?: WebhookOptions): void;\n      };\n      if (typeof adapter.processUpdate !== \"function\") {\n        throw new Error(\n          \"Telegram authenticated dispatch contract is unavailable\",\n        );\n      }\n      const processUpdate = adapter.processUpdate.bind(this.adapter);\n      adapter.processUpdate = (update, webhookOptions) => {\n        // The pinned webhook verifier calls processUpdate only after checking\n        // the secret. No parser-normalized chat:0 input may enter ordinary work.\n        if (hasTelegramEphemeralInput(update)) return;\n        const attempt = this.webhookIngress.getStore();\n        if (isRecord(update) && \"stopped_message_generation\" in update) {\n          // This wrapper is reached only after the pinned webhook secret check.\n          // Join the durable callback to the same HTTP acknowledgement barrier.\n          const proof =\n            attempt && adapter.botUserId\n              ? captureTelegramGenerationStopped(adapter.botUserId, update)\n              : null;\n          if (proof && options.callbacks.onTelegramGenerationStopped) {\n            const task = Promise.resolve().then(() =>","sourceCodeStart":2076,"sourceCodeEnd":2112,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-sdk-runtime.ts#L2076-L2112","documentation":"For Telegram, authenticated webhook dispatch relies on the adapter exposing processUpdate(update, options). Before the runtime wraps processUpdate with its pinned webhook verifier, it asserts the method exists on the adapter; if not, this error is thrown, indicating the adapter does not fulfill the authenticated dispatch contract.","triggerScenarios":"Starting the Telegram webhook path where adapter.processUpdate is undefined or not a function — e.g. the adapter object lacks the method or is the wrong class entirely.","commonSituations":"Swapped/legacy adapter implementation without processUpdate; adapter upgrade where the method was renamed; misconfiguration causing a base adapter (not the Telegram one) to be registered under provider 'telegram'; tree-shaken/bundled builds dropping the method.","solutions":["Ensure the adapter registered for provider 'telegram' is the real Telegram adapter exposing processUpdate.","Upgrade/repair the adapter package to a version that includes processUpdate.","Check adapter registration/config so the provider name matches the adapter class actually instantiated.","If using a custom adapter, implement processUpdate(update: unknown, options?: WebhookOptions): void."],"exampleFix":"// before\nthis.adapter = new GenericPollingAdapter(); // no processUpdate\n// after\nthis.adapter = new TelegramAdapter(); // exposes processUpdate(update, options)","handlingStrategy":"type-guard","validationCode":"const a = adapter as { processUpdate?: unknown };\nif (typeof a.processUpdate !== \"function\") {\n  throw new Error(\"registered telegram adapter lacks processUpdate\");\n}","typeGuard":"function hasProcessUpdate(a: unknown): a is { processUpdate(update: unknown, options?: unknown): void } {\n  return typeof a === \"object\" && a !== null && typeof (a as any).processUpdate === \"function\";\n}","tryCatchPattern":"try {\n  telegramRuntime.startWebhook();\n} catch (err) {\n  if (/authenticated dispatch contract/.test(String(err?.message))) {\n    logger.error(\"telegram adapter missing processUpdate; check adapter registration\");\n  }\n  throw err;\n}","preventionTips":["Register the real Telegram adapter for provider 'telegram', not a generic base class.","Check processUpdate presence in an adapter smoke test.","Keep adapter and runtime versions in lockstep."],"tags":["telegram","webhook","adapter-contract"],"backgroundTag":"method-not-implemented","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"}