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.
Summary
tg downloadhangs forever, writes a zero-byte file and prints no error wheneverthe 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.
Cause
Not in this repo.
floodwait.Waiter's send loop callsInvokesynchronously, soit cannot dispatch anything else until that call returns.
FILE_MIGRATEis theone path where
gotd/tdstarts an invoke from inside an in-flight invoke:exportAuthgoes throughc.invoker, the middleware-wrapped invoker, so itre-enters
Waiter.Handlewhile the send loop is still blocked onupload.getFile. The nested call can never be scheduled; the outer call cannever return. Neither errors, so there is nothing to log.
With
zapat debug level the trace stops dead:Ruled out along the way: network (all DCs reachable on 443), transport
(
TDesktopResolverand gotd's default behave identically), rate limiting (theflood-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/cliv0.11.0 downloads the same photo in 4.1 seconds. Nochange 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)incmd/tg/app.goalso resolves it, sinceSimpleWaiterretries inline and isre-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,
downloadleaves 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.