{"record":{"id":"65a98e681d50f723","repo":"mastra-ai/mastra","slug":"no-telegram-installation-found-for-agent-agenti","errorCode":null,"errorMessage":"No Telegram installation found for agent \"${agentId}\"","messagePattern":"No Telegram installation found for agent \"(.+?)\"","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/telegram/src/telegram-provider.ts","lineNumber":268,"sourceCode":"    };\n\n    // Register the transport before persisting so a Bot API failure surfaces to\n    // the caller instead of leaving a half-connected install.\n    await this.#registerTransport(installation, mode);\n    await this.#registerCommands(installation);\n    await store.save(installation);\n    await this.#activateInstallation(installation);\n    this.#configured = true;\n    await this.#config.onInstall?.(installation);\n    return { type: 'immediate', installationId };\n  }\n\n  /** Disconnect an agent from Telegram, removing its webhook and installation. */\n  async disconnect(agentId: string): Promise<void> {\n    const store = await this.#getStore();\n    const existing = await store.getByAgent(agentId);\n    if (!existing) {\n      throw new Error(`No Telegram installation found for agent \"${agentId}\"`);\n    }\n    // Stop the polling loop (no-op in webhook mode) so it isn't orphaned.\n    const adapter = this.#adapters.get(existing.id);\n    if (adapter) {\n      try {\n        await adapter.stopPolling();\n      } catch (err) {\n        console.warn(`[Telegram] Failed to stop polling for agent \"${agentId}\":`, err);\n      }\n    }\n    if (existing.botToken) {\n      try {\n        await deleteWebhook(existing.botToken, true, this.#apiBaseUrl());\n      } catch (err) {\n        console.warn(`[Telegram] Failed to delete webhook for agent \"${agentId}\":`, err);\n      }\n    }\n    this.#adapters.delete(existing.id);","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/telegram/src/telegram-provider.ts#L250-L286","documentation":"disconnect(agentId) looks up the Telegram installation for the agent in the store. If none exists, there is nothing to remove (no webhook to delete, no polling loop to stop), so it throws rather than silently succeeding. It signals the agent was never connected or the installation was already removed.","triggerScenarios":"Calling provider.disconnect(agentId) for an agent that never called connect(); disconnecting after a prior disconnect already deleted the installation; agent ID typo or using a different agentId string than the one used at connect time; the store was cleared/reset.","commonSituations":"Cleanup/teardown code running against a fresh environment; multi-tenant apps where the agent was registered under a different ID; stale references after wiping local storage in dev.","solutions":["Guard the disconnect with a lookup and only disconnect when an installation exists","Confirm the exact agentId string used when connect() succeeded","Treat this as already-disconnected and ignore it if cleanup idempotency is the goal (wrap in try/catch)","If records should exist, inspect the configured store (e.g. in-memory vs persistent) — a different store instance may hold the installation"],"exampleFix":"// before\nawait provider.disconnect(agentId);\n// after\ntry {\n  await provider.disconnect(agentId);\n} catch {\n  // already disconnected / never connected — safe to ignore\n}","handlingStrategy":"try-catch","validationCode":"const existing = await store.getByAgent(agentId);\nif (existing) await provider.disconnect(agentId);","typeGuard":"function isInstalled(i: unknown): i is { id: string; status: string } {\n  return typeof i === 'object' && i !== null && 'id' in i;\n}","tryCatchPattern":"try {\n  await provider.disconnect(agentId);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('No Telegram installation found')) {\n    return; // already disconnected — make teardown idempotent\n  }\n  throw err;\n}","preventionTips":["Track connection state in your app and only disconnect when connected","Use the same agentId constant/source for connect and disconnect","Make cleanup hooks idempotent so double teardown is harmless","If installations should persist, confirm the same store instance is used across the process lifetime"],"tags":["telegram","state-conflict","cleanup"],"backgroundTag":"resource-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}