hcengineering/platform · error
Failed to fetch photo
Error message
Failed to fetch photo
What it means
The telegram-bot photo endpoint fetches a file from the Telegram Bot API (getFile/download) and pipes it to the response. When the upstream fetch response is not OK, the handler sends HTTP 500 with the plain text 'Failed to fetch photo' instead of streaming the image.
Source
Thrown at services/telegram-bot/pod-telegram-bot/src/server.ts:172
'/photo/:fileId',
wrapRequest(async (req, res) => {
const { fileId } = req.params
const fileLink = await bot.telegram.getFileLink(fileId)
const response = await fetch(fileLink.toString())
if (!response.ok) {
res.status(response.status).send(response.statusText)
return
}
if (response.body != null) {
res.setHeader('Content-Type', response.headers.get('Content-Type') ?? 'application/octet-stream')
res.setHeader('Content-Length', response.headers.get('Content-Length') ?? '0')
const stream = Readable.fromWeb(response.body as ReadableStream<any>)
stream.pipe(res)
} else {
res.status(500).send('Failed to fetch photo')
}
})
)
app.use((err: any, _req: any, res: any, _next: any) => {
if (err instanceof ApiError) {
res.status(err.code).send({ code: err.code, message: err.message })
return
}
res.status(500).send(err.message?.length > 0 ? { message: err.message } : err)
})
return app
}
export function listen (e: Express, ctx: MeasureContext, port: number, host?: string): Server {
const cb = (): void => {View on GitHub (pinned to 63e28dc964)
Solutions
- Verify the BOT_TOKEN environment variable is valid and the bot can call getMe.
- Check that the file_id/path parameter passed to the Telegram getFile call is current — re-resolve it via getFile before downloading.
- Test outbound connectivity from the pod to api.telegram.org (DNS/proxy/firewall).
- Add logging of the upstream response.status in the else branch to distinguish 401 (token) from 400 (bad file_id) and retry once with a fresh getFile.
Example fix
// before
} else {
res.status(500).send('Failed to fetch photo')
}
// after
} else {
console.error('photo fetch failed', response.status)
if (response.status === 404) { /* re-getFile and retry once */ }
res.status(502).send(`Failed to fetch photo: upstream ${response.status}`)
} Defensive patterns
Strategy: retry
Validate before calling
async function canReachTelegram(): Promise<boolean> {
const r = await fetch(`https://api.telegram.org/bot${process.env.BOT_TOKEN}/getMe`)
return r.ok
}
if (!(await canReachTelegram())) throw new Error('BOT_TOKEN invalid or Telegram unreachable') Type guard
function isOkResponse(r: Response): r is Response & { ok: true } { return r.ok } Try / catch
const r = await fetch(photoUrl)
if (!r.ok) {
if (r.status === 404) { /* re-getFile, retry once */ }
throw new Error(`photo upstream failed: ${r.status}`)
} Prevention
- Always re-resolve file_path via getFile immediately before download — Telegram file links expire (~1 hour).
- Validate BOT_TOKEN at bot startup with getMe and fail fast.
- Add monitoring for egress connectivity to api.telegram.org from the pod.
- Distinguish upstream status codes in the error message instead of a generic 500.
When it happens
Trigger: A client requests the photo route while the fetch to Telegram's file API returns a non-OK status — expired/invalid bot token, invalid file_id, Telegram network failure, or file too large to download via the Bot API.
Common situations: Telegram file_path expiring (file links are valid for ~1 hour), BOT_TOKEN misconfigured in the bot pod environment, avatar/photo id from an old message whose file is no longer resolvable, or network egress from the pod to api.telegram.org blocked.
Related errors
- response.statusText
- Failed to fetch config
- unknownError(response.statusText)
- Failed to delete file
- Failed to delete file
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/1b6929f43ec39aae.
Report an issue: GitHub.