Conversation
ErrorCodeToLinkError has no case for 400, so it falls through to the permanent default. TorBox returns a bare 400 when a presigned download link has expired or rotated, which is a refetchable condition. A permanent classification fast-trips the VFS circuit breaker (errorCount = maxErrorCount) and is memoized in s.validated, where only ShouldRefetch() invalidates it, so one stale link makes the file read 0 bytes until cooldown instead of refetching. This aligns the provider-API path with ClassifyStreamStatus, which already treats 400 at the CDN layer as refetchable.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📌 Description
ErrorCodeToLinkErrorhas no case for400, so it falls through to thedefault:permanent branch. TorBox returns a bare400when a presigneddownload link has expired or rotated — a refetchable condition — so a merely
stale link is treated as a dead file.
Target Branch Check (IMPORTANT)
Expected target:
Changes Made
400toNewRefetchableErrorinErrorCodeToLinkErrorErrLinkRejectedsentinel alongside the existingErr404/Err429/Err503This makes the provider-API path agree with the CDN path, which already gets
this right —
ClassifyStreamStatusclassifies 400 as refetchable with thecomment "4xx auth-shaped statuses and 404 usually mean the presigned link
expired or rotated". Only the
validateLinkHEAD path disagreed.Why permanent is harmful here
countErrorsfast-trips the circuit breaker on a permanent error:and
fetchAndValidatememoizes the result ins.validated, where onlyShouldRefetch()invalidates it. So one stale link makes the file read0 bytes until cooldown instead of just refetching. Symptom in the *arrs is
Unable to determine if file is a sample/ stuckimportPending, becausethe sample check can't read byte 0.
Testing
Steps:
Confirmed TorBox returns 400 specifically for a bad/expired presigned link,
while the torrent itself is healthy (
mylist→state=cached,download_present=true):requestdllink, bytes 0-1MB206, 1048576 bytes400tokenstripped400 missing field 'token'Added a temporary unit test on
ErrorCodeToLinkError: it fails on currentbeta(400 must be refetchable, got category permanent) and passes withthis change, with
404/429/unknown-code behaviour unchanged. Removedbefore committing.
Built the image from this branch and ran it against a live TorBox account.
Two files that previously returned
Input/output error/ 0 bytes now readat full speed (2.6 MB/s and 3.9 MB/s), and
400: unknown error code: 400went to zero across the whole mount. Remaining errors under a deliberate
read burst were
429, which retries correctly.Risks / Notes
400; all other codes unchanged.before failing, rather than failing immediately. That is bounded by the
existing attempt budget in
fetchAndValidate, and matches how the CDNlayer has always handled 400.
read_pxy_timeout.Checklist