Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions apps/sim/blocks/blocks/telegram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,14 @@ export const TelegramBlock: BlockConfig<TelegramResponse> = {
}
case 'telegram_send_photo': {
// photo is the canonical param for both basic (photoFile) and advanced modes
// In advanced mode, photo can be a plain URL string or file_id
if (typeof params.photo === 'string' && params.photo.trim()) {
return {
...commonParams,
photo: params.photo.trim(),
caption: params.caption,
}
}
Comment on lines +274 to +280
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON-serialized file object strings bypassed prematurely

The check typeof params.photo === 'string' && params.photo.trim() intercepts any non-empty string — including a JSON-serialized file object that template resolution might produce when a user references a file-typed block output (e.g. <uploadBlock.result.file> resolves to '{"name":"photo.jpg","url":"blob:..."}').

In that case the raw JSON string gets forwarded to the Telegram API as the photo value, which Telegram will reject as an invalid URL or file_id.

A slightly more defensive guard tries to parse the string first and only short-circuits when the result is still a string (or parsing fails):

Suggested change
if (typeof params.photo === 'string' && params.photo.trim()) {
return {
...commonParams,
photo: params.photo.trim(),
caption: params.caption,
}
}
// In advanced mode, photo can be a plain URL string or file_id.
// Only bypass normalizeFileInput when the value is *not* a JSON-encoded object/array.
if (typeof params.photo === 'string' && params.photo.trim()) {
let directValue: string | null = null
try {
const parsed = JSON.parse(params.photo)
// A JSON-encoded string is still a valid passthrough (e.g. `"https://..."`)
if (typeof parsed === 'string') directValue = parsed
} catch {
// Not valid JSON → plain URL or file_id
directValue = params.photo.trim()
}
if (directValue) {
return {
...commonParams,
photo: directValue,
caption: params.caption,
}
}
}

The same pattern applies to the video, audio, and animation cases below. Note that even without this change both paths would ultimately fail for a file-object reference (since the Telegram API only accepts string identifiers), but the refined guard makes the intent explicit and avoids silently forwarding malformed values.

const photoSource = normalizeFileInput(params.photo, {
single: true,
})
Expand All @@ -284,6 +292,14 @@ export const TelegramBlock: BlockConfig<TelegramResponse> = {
}
case 'telegram_send_video': {
// video is the canonical param for both basic (videoFile) and advanced modes
// In advanced mode, video can be a plain URL string or file_id
if (typeof params.video === 'string' && params.video.trim()) {
return {
...commonParams,
video: params.video.trim(),
caption: params.caption,
}
}
const videoSource = normalizeFileInput(params.video, {
single: true,
})
Expand All @@ -298,6 +314,14 @@ export const TelegramBlock: BlockConfig<TelegramResponse> = {
}
case 'telegram_send_audio': {
// audio is the canonical param for both basic (audioFile) and advanced modes
// In advanced mode, audio can be a plain URL string or file_id
if (typeof params.audio === 'string' && params.audio.trim()) {
return {
...commonParams,
audio: params.audio.trim(),
caption: params.caption,
}
}
const audioSource = normalizeFileInput(params.audio, {
single: true,
})
Expand All @@ -312,6 +336,14 @@ export const TelegramBlock: BlockConfig<TelegramResponse> = {
}
case 'telegram_send_animation': {
// animation is the canonical param for both basic (animationFile) and advanced modes
// In advanced mode, animation can be a plain URL string or file_id
if (typeof params.animation === 'string' && params.animation.trim()) {
return {
...commonParams,
animation: params.animation.trim(),
caption: params.caption,
}
}
const animationSource = normalizeFileInput(params.animation, {
single: true,
})
Expand Down