Skip to content

@elizaos/plugin-telegram (Telegraf 4.16.3) bot.launch() throws 'Attempted to assign to readonly property' under Bun #7241

@Sw4pIO

Description

@Sw4pIO

Summary

@elizaos/plugin-telegram's startup wrapper calls bot.launch({...}) on a Telegraf instance (Telegraf 4.16.3). Under Bun 1.3.13 this rejects with:

[milady] Telegram bot launch error: Attempted to assign to readonly property.

The bot never starts polling. From the user side, the bot looks alive on Telegram (Telegram's getUpdates queues messages waiting for it) but the runtime never receives them. No replies. UI may report "Connected" because the token is valid; the actual long-poll never started.

Root cause

telegraf@4.16.3/lib/telegraf.js:189 (compiled output of nullish-coalescing-assignment):

async launch(config = {}, onLaunch) {
    var _a, _b;
    ...
    debug('Connecting to Telegram');
    (_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = await this.telegram.getMe());
    ...
}

The expression assigns to this.botInfo. Under Bun's CJS interop the Telegraf prototype/instance ends up with a non-writable descriptor on certain inherited fields, and the assignment trips a strict-mode TypeError: Attempted to assign to readonly property. Same code paths work under Node.

Reproduction

  1. Fresh milady (alice or develop), Telegram connector enabled with a valid BotFather token (in env.TELEGRAM_BOT_TOKEN per telegram bot token not bridged from dashboard config to runtime — UI says 'connected' while plugin says 'Bot token not provided' #7240).
  2. bun run dev
  3. Boot log:
    [PLUGIN:TELEGRAM] Starting Telegram bot
    [milady] Telegram bot polling started
    [Warn] [milady] Telegram bot launch error: Attempted to assign to readonly property.
    
  4. DM the bot from Telegram — no inbound message appears in logs.
  5. curl https://api.telegram.org/bot<token>/getUpdates shows the messages queued, confirming the bot itself is reachable but its long-poll never started.

Workaround (verified locally)

In eliza/packages/app-core/src/runtime/eliza.ts (or wherever the wrapper is), bypass bot.launch() and start polling directly:

(async () => {
  try {
    await bot.telegram.deleteWebhook({ drop_pending_updates: true });
  } catch (err) {
    logger.warn(`[milady] Telegram deleteWebhook failed: ${...}`);
  }
  try {
    // @ts-expect-error - startPolling is intentionally public for this fallback
    bot.startPolling(["message", "message_reaction"]);
  } catch (err) {
    logger.warn(`[milady] Telegram startPolling failed: ${...}`);
  }
})();

This skips the (this.botInfo ??= ...) assignment that triggers the Bun strict-mode reject. Same behavior as launch() (long-poll mode, no webhook), without the error. Verified inbound messages reach the runtime and replies go back.

Suggested upstream fix

Two options for the plugin layer:

  1. Wrap bot.launch() to use the explicit polling path on Bun:

    const isBun = typeof process !== "undefined" && Boolean((process as any).versions?.bun);
    if (isBun) {
      await bot.telegram.deleteWebhook({ drop_pending_updates: true });
      bot.startPolling(["message", "message_reaction"]);
    } else {
      await bot.launch({ dropPendingUpdates: true, allowedUpdates: ["message", "message_reaction"] });
    }
  2. Pin/upgrade Telegraf — the issue may be fixed in a newer release with a different compiled output. Worth testing against the latest 4.x and 5.x previews.

Option 1 is the safer immediate fix; option 2 is the right long-term move.

Why this matters

This silently breaks every Bun-hosted milady install with a Telegram connector. The auto-enable log says the plugin is loaded, the dashboard says "connected", but no messages ever flow. Users have no way to diagnose this without log access, and the failure mode (warning, not error; "polling started" log fires before the launch reject because launch() is fire-and-forget) hides the bug effectively.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions