HKUDS/Vibe-Trading · critical · ValueError

webhook_secret_token is required when Telegram mode is webho

Error message

webhook_secret_token is required when Telegram mode is webhook

What it means

Raised by TelegramChannel config validation when mode is webhook but webhook_secret_token is empty or whitespace-only. The secret token is used with Telegram's setWebhook secret_token so the bot can verify update requests actually came from Telegram. Without it, anyone who discovers the webhook URL could post forged updates, so the library refuses to start.

Source

Thrown at agent/src/channels/telegram.py:415

        value = value.strip() or "/telegram"
        if not value.startswith("/"):
            raise ValueError('webhook_path must start with "/"')
        return value

    @model_validator(mode="after")
    def validate_webhook_config(self) -> "TelegramConfig":
        if self.mode != "webhook":
            return self

        url = self.webhook_url.strip()
        if not url:
            raise ValueError("webhook_url is required when Telegram mode is webhook")
        parsed = urlparse(url)
        if parsed.scheme != "https" or not parsed.netloc:
            raise ValueError("webhook_url must be a public HTTPS URL")
        secret = self.webhook_secret_token.strip()
        if not secret:
            raise ValueError("webhook_secret_token is required when Telegram mode is webhook")
        if len(secret) > 256 or re.match(r"^[A-Za-z0-9_-]+$", secret) is None:
            raise ValueError(
                "webhook_secret_token must be 1-256 characters using only A-Z, a-z, 0-9, _ and -"
            )
        return self


class TelegramChannel(BaseChannel):
    """
    Telegram channel using long polling or webhook mode.

    Long polling is the default. Webhook mode requires a public HTTPS URL and a
    Telegram secret token.
    """

    name = "telegram"
    display_name = "Telegram"

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Set webhook_secret_token to a random token, e.g. generate with openssl rand -hex 32 (matches [A-Za-z0-9_-])
  2. Verify the env var actually resolves in the runtime environment (print it or use the same loader the app uses)
  3. If you truly want polling instead of webhooks, set mode to polling rather than leaving webhook without a secret

Example fix

# before
TelegramConfig(mode="webhook", webhook_url="https://bot.example.com/tg/hook")
# after
import secrets
TelegramConfig(
    mode="webhook",
    webhook_url="https://bot.example.com/tg/hook",
    webhook_secret_token=secrets.token_urlsafe(32),
)
Defensive patterns

Strategy: validation

Validate before calling

import secrets
from agent.src.channels.telegram import TelegramConfig  # adjust import

def make_tg_config(**kw) -> TelegramConfig:
    if kw.get("mode") == "webhook" and not (kw.get("webhook_secret_token") or "").strip():
        kw["webhook_secret_token"] = secrets.token_hex(32)  # auto-provision
    return TelegramConfig(**kw)

Type guard

def has_webhook_secret(cfg: dict) -> bool:
    return cfg.get("mode") != "webhook" or bool(str(cfg.get("webhook_secret_token", "")).strip())

Prevention

When it happens

Trigger: Constructing the Telegram channel config with mode="webhook" (or TELEGRAAM/webhook env config) while webhook_secret_token is unset, empty, or only spaces. The model validator strips the value and raises when the result is falsy.

Common situations: Copying a polling-mode config to webhook mode and forgetting the secret; providing the secret via an env var name that isn't set (expands to empty string); secrets loaded from a .env file that isn't loaded in the deploy environment.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/d6c290e58be81805. Report an issue: GitHub.