Skip to content

fix(stream): answer 502 when Telegram fails before the first byte - #650

Open
aZuiZui wants to merge 1 commit into
tgdrive:mainfrom
aZuiZui:fix/stream-error-before-first-byte
Open

aZuiZui wants to merge 1 commit into
tgdrive:mainfrom
aZuiZui:fix/stream-error-before-first-byte

Conversation

@aZuiZui

@aZuiZui aZuiZui commented Nov 13, 2026

Copy link
Copy Markdown

Some of my older files have a part Telegram won't serve any more: every chunk comes back as -503 Timeout, or the message is gone. In 2.x the stream has already written 206 and the headers by then, so the client gets an empty body that just ends. rclone treats it as a short read and keeps retrying, and the log only says context deadline exceeded.

This PR:

  • reads the first 64 KiB before writing the status line. If that read fails, the response is 502 (telegram_part_unavailable for a -503 or a missing message, telegram_read_failed otherwise) and api.stream_unreadable is logged with the file id. Errors that already have their own status (504 etc.) keep it.
  • does the same when opening the file fails because a part's size had to be looked up and the message is gone (older uploads without stored sizes). That was a 500.
  • keeps the Telegram error when the retry middleware's deadline runs out while it's retrying a -503. It now reads as rpc error code -503: Timeout (retried until the deadline) and still matches errors.Is(err, context.DeadlineExceeded) and tgerr.As.
  • adds the message id to the part errors, so the log says which message is broken.

Normal streams only change in that the first 64 KiB are read before the headers go out.

Tested with unit tests for the stream handler and the retry middleware, and with go test -race -tags=integration for api, telegramstore and transfer. I also tried it on a test instance by pointing a part at a message that doesn't exist: before it was a 500 (or an empty 206), now it's a 502 every time, and the file reads normally again once the part is fixed.

When Telegram can't serve a part (-503 Timeout after the retries, or its
message is gone), the stream had already sent 206 and its headers, so the
client got an empty body cut short and had to guess. rclone retried it as a
short read over and over.

- Read the first 64 KiB before writing the status line. If that fails, answer
  502 (telegram_part_unavailable / telegram_read_failed) and log
  api.stream_unreadable. Errors with their own status (504 etc.) keep it.
- The same for a part whose size is looked up on open (older uploads) and is
  gone: it was a 500.
- The retry middleware returned a bare "context deadline exceeded" when the
  deadline ran out while it retried a -503, so the reason was lost. It now
  returns an error that reads as the Telegram error and still matches both
  (errors.Is deadline, tgerr.As).
- Part errors name the message id.
bioidaika added a commit to bioidaika/teldrive that referenced this pull request Nov 14, 2026
…rors

- PR tgdrive#650: stream pre-reading returns 502 Bad Gateway instead of 206 when Telegram part is gone or unavailable before first byte

- PR tgdrive#650: preserve Telegram RPC errors across retry deadline expirations

- PR tgdrive#650: include message ID in download error logs

- Issue tgdrive#651: add 'teldrive backfill-part-sizes' command to batch-resolve missing part sizes via Telegram into database

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant