download hangs forever on cross-datacenter files (zero-byte output, no error)
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 34
- Forks
- 6
- PR merge metrics
- No merged PRs in 30d
Description
Summary
tg download hangs forever, writes a zero-byte file and prints no error whenever
the file lives on a datacenter other than the account's home DC. In practice that
is most media, since a file's DC frequently differs from the account's.
Reproduced on v0.11.0, macOS arm64, against a real account (home DC 4, file on
DC 5), on two different photos.
$ tg download @somechannel 1073 --out ./dl/
<hangs indefinitely>
$ ls -la dl/
-rw-r--r-- 0 photo_6136248896133469079.jpg
Cause
Not in this repo. floodwait.Waiter's send loop calls Invoke synchronously, so
it cannot dispatch anything else until that call returns. FILE_MIGRATE is the
one path where gotd/td starts an invoke from inside an in-flight invoke:
upload.getFile -> FILE_MIGRATE_5
telegram/invoke.go invokeDirect -> invokeSub(targetDC)
telegram/pool.go dc -> createPool
telegram/transfer.go transfer -> auth.exportAuthorization
exportAuth goes through c.invoker, the middleware-wrapped invoker, so it
re-enters Waiter.Handle while the send loop is still blocked on
upload.getFile. The nested call can never be scheduled; the outer call can
never return. Neither errors, so there is nothing to log.
With zap at debug level the trace stops dead:
Got error err_code=303 err_msg=FILE_MIGRATE_5
telegram/invoke.go:71 Invoking on target DC target_dc=5
telegram/pool.go:75 Creating pool dc_id=5 max=1
<no dial, no error, no further traffic>
Ruled out along the way: network (all DCs reachable on 443), transport
(TDesktopResolver and gotd's default behave identically), rate limiting (the
flood-wait callback never fires), and chunk size (512/128/64/32 KiB all hang).
Fix
gotd/contrib#773 makes the waiter handle re-entrant invokes. With that branch,
unmodified gotd/cli v0.11.0 downloads the same photo in 4.1 seconds. No
change is needed in this repo once it lands and is released.
If an interim fix is wanted here before then, swapping floodwait.NewWaiter()
for floodwait.NewSimpleWaiter().WithMaxWait(time.Minute).WithMaxRetries(5) in
cmd/tg/app.go also resolves it, since SimpleWaiter retries inline and is
re-entrant. That trades away global flood coordination, so the contrib fix is
the better one. Happy to send either as a PR if useful.
Unrelated, smaller
While testing, download leaves its zero-byte output file behind on failure.
Worth deleting a partial file on error regardless of this bug, since an empty
file is indistinguishable from a slow network.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by checking gotd/contrib#773 and whether its re-entrant waiter fix is released, since the issue says no repository change is needed afterward. If an interim fix is preferred, inspect cmd/tg/app.go around floodwait.NewWaiter and verify a cross-datacenter download completes; also consider the separately noted zero-byte cleanup on failure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100