mastra-ai/mastra · error
TelegramProvider needs a baseUrl to register a webhook. Set
Error message
TelegramProvider needs a baseUrl to register a webhook. Set `baseUrl`, configure the Mastra server, or use `mode: "polling"`.
What it means
In webhook mode, Telegram must be able to POST updates back to your server, which requires a publicly reachable baseUrl. resolveMode() selects 'webhook' when a baseUrl is present (or the configured mode demands it), and if mode is webhook but baseUrl is empty/undefined, connect() cannot build the webhook URL `${baseUrl}/telegram/events/${webhookId}` and throws.
Source
Thrown at channels/telegram/src/telegram-provider.ts:233
if (!options.botToken) {
const installationId = existing?.id ?? randomUUID();
await store.save({
id: installationId,
agentId,
webhookId: existing?.webhookId ?? randomUUID(),
status: 'pending',
installedAt: existing?.installedAt ?? new Date(),
});
return { type: 'deep_link', url: BOTFATHER_DEEP_LINK, installationId };
}
const me = await getMe(options.botToken, this.#apiBaseUrl());
const installationId = existing?.id ?? randomUUID();
const webhookId = existing?.webhookId ?? randomUUID();
const baseUrl = this.#getBaseUrl();
const mode = this.#resolveMode(baseUrl);
if (mode === 'webhook' && !baseUrl) {
throw new Error(
'TelegramProvider needs a baseUrl to register a webhook. Set `baseUrl`, configure the Mastra server, or use `mode: "polling"`.',
);
}
const webhookUrl = mode === 'webhook' ? `${baseUrl}/${PLATFORM}/events/${webhookId}` : undefined;
const commands = normalizeCommands(options.commands ?? this.#config.commands ?? DEFAULT_COMMANDS);
const installation: TelegramInstallation = {
id: installationId,
agentId,
webhookId,
status: 'active',
botToken: options.botToken,
secretToken: generateSecretToken(),
username: options.name ?? me.username ?? me.first_name,
webhookUrl,
commands: commands.length ? commands : undefined,
installedAt: existing?.installedAt ?? new Date(),
};
View on GitHub (pinned to 75dd419e61)
Solutions
- Pass a public baseUrl to the TelegramProvider options (must be reachable by Telegram servers)
- Configure the Mastra server so the library can infer its public URL
- Explicitly switch to long polling for local dev: mode: 'polling' in the provider config or connect options
- For local testing, expose the server via a tunnel (e.g. ngrok) and use the tunnel URL as baseUrl
Example fix
// before
const provider = new TelegramProvider({ botToken });
// after
const provider = new TelegramProvider({ botToken, mode: 'polling' });
// or, for webhooks:
const provider = new TelegramProvider({ botToken, baseUrl: 'https://my-app.example.com' }); Defensive patterns
Strategy: validation
Validate before calling
if (mode === 'webhook' && !baseUrl) {
throw new Error('Provide a public baseUrl (or use mode: "polling") before connecting');
} Type guard
function hasPublicBaseUrl(o: { baseUrl?: string; mode?: string }): boolean {
return o.mode === 'polling' || typeof o.baseUrl === 'string' && o.baseUrl.startsWith('https://');
} Try / catch
try {
await provider.connect(agentId, { botToken });
} catch (err) {
if (err instanceof Error && err.message.includes('needs a baseUrl')) {
await provider.connect(agentId, { botToken, mode: 'polling' }); // dev fallback
return;
}
throw err;
} Prevention
- Set the public BASE_URL env var in every deployed environment
- Use polling mode locally and webhook mode in production via env-driven config
- Verify the baseUrl is reachable by Telegram (public https, not localhost)
- Point a tunnel (ngrok etc.) at the dev server if webhooks are needed locally
When it happens
Trigger: Instantiating TelegramProvider without a baseUrl option and without a Mastra server configured, while mode resolves to 'webhook' (the default when a URL is expected); calling connect() in an environment with no server URL set.
Common situations: Local development without a public URL (no tunneling); deployed app missing the BASE_URL/public URL env var; serverless/edge setup where the library cannot infer the Mastra server address.
Related errors
- Telegram installation secrets are encrypted at rest, but no
- Telegram getMe returned a non-bot user; expected a BotFather
- Agent "${agentId}" is already connected to Telegram. Disconn
- Platform integration: missing required environment variable
- AcpAgent does not support resuming suspended generate calls
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/cfc87087e3df4b4a.
Report an issue: GitHub.