Multi-Hoster-Upload/tests
Administrator 8b2a1d7c1f fix(byse): treat 5xx/gateway upload failures as transient infra, not account faults
A single byse.sx gateway hiccup (HTTP 502 "<!doctype html>..." or a mid-upload
ECONNRESET) was cascading through the whole failover chain and blacklisting every
account for the batch. Root cause: the upload-POST throw sites threw PLAIN errors
with no classification, so a 502 was treated as a GENERIC error -> mark-failed ->
emit('account-failed') -> failover to the next account (which hits the same
gateway) -> repeat until the chain is exhausted, then poison sibling files in the
batch via the blacklist. The screenshots showed exactly this: "Primär ... Fallback
#3" all failing with the same 502. byse did NOT change their API (the upload
contract still matches their docs and was live-probed: GET /upload/server -> POST
{key}+file -> files[0].filecode); these are transient infrastructure failures.

A 5xx gateway error is not an account fault: every account hits the same gateway,
so failing over is pointless and blacklisting is harmful. Fail open instead — retry
the SAME account and, if byse stays down, fail the file cleanly without touching the
account or the rotation cursor.

- upload-manager: _isTransientNetworkError() now honors an explicit err.transientNetwork
  flag (checked before the empty-message guard) and, as a defensive fallback, matches
  /HTTP 5\d\d/, Bad Gateway, Service Unavailable, Gateway Time-out. The flag is made
  authoritative in _isFileRejectedError and _shouldSkipRetryOnAccountError (both return
  early when it is set) so a 5xx whose HTML body happens to contain a rejection/auth
  keyword can never be mis-binned as file/account. The post-rotation retry loop also
  breaks on a transient error (parity with the primary loop) to avoid burning the
  retry budget re-uploading on a fallback.
- hosters: the upload POST throw sites tag err.transientNetwork when statusCode >= 500
  (non-JSON body and non-2xx-with-JSON) and when the 2xx status-envelope carries
  status:500; 401/403/429 stay PLAIN so they remain account errors. The server-lookup
  path (apiGet/getUploadServer) is hardened symmetrically: a 5xx there tags
  transientNetwork and getUploadServer preserves the flag onto its wrapped error, so
  the heuristic shouldRetryServerLookup() can no longer be defeated by a 5xx body that
  contains an auth keyword.
- hosters: fixed a separate real bug surfaced during investigation — _fetchByseFileList
  built the wrong URL https://api.byse.sx/api/file/list (the /api/ prefix is correct
  only for doodstream's doodapi.co host; byse already carries the api. subdomain).
  Live-probed: /api/file/list 302-redirects to the docs page, /file/list returns 200
  JSON. The wrong path made the byse async-recovery poll silently dead (always []),
  removing the safety net that reclaims a large file that registered despite a 502.
  Now https://api.byse.sx/file/list.

ECONNRESET was already transient and is unchanged. doodstream's 2xx empty-form stays
hosterTransient (one attempt, no re-upload). vidmoly/clouddrop use their own uploaders
and are unaffected; doodstream/voe apiKey uploads share uploadFile and correctly
benefit from the same 5xx-is-infra logic.

Deferred follow-up: poll-first-on-5xx dedup (route a 5xx through the now-working
recovery poll before retrying, to reclaim a registered-but-502 file instead of
re-uploading). It does not add new dupe risk vs the prior cascade and a pure 502
means the backend was never reached, so retry-same-account is dupe-safe for it.

Investigated and reviewed by two multi-agent workflows (4-lens investigation with a
synthesized fix spec; 4-lens adversarial review with per-finding verification): no
API drift, 0 confirmed defects. Tests: classifier units (flag-above-message-guard,
5xx-transient, 4xx-stay-account), an end-to-end 502/503/500-envelope tag through
uploadFile, and a 502-retries-same-account-no-cascade integration case. Suite 311/311.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 01:56:11 +02:00
..
account-auth.test.js fix(doodstream): upload via the doodapi API when an API key exists 2026-05-28 21:42:19 +02:00
account-rotation.test.js fix(rotation): persist the round-robin cursor so drip-fed uploads keep rotating 2026-06-17 03:33:20 +02:00
backup-crypto.test.js feat(backup): import legacy password-encrypted backups 2026-04-17 11:22:33 +02:00
byse-reject-recovery.test.js fix(byse): treat 5xx/gateway upload failures as transient infra, not account faults 2026-06-19 01:56:11 +02:00
coalesced-set.test.js test(coalesce): extract done-removal coalescer + 11 unit tests 2026-04-28 11:59:32 +02:00
config-store.test.js feat(rotation): per-hoster toggle to disable the "Bekanntes Größen-Limit" pre-skip 2026-06-17 13:41:38 +02:00
doodstream-api-upload.test.js test(doodstream): end-to-end integration test for the API upload + recovery path 2026-05-28 22:20:21 +02:00
doodstream-upload.test.js fix(doodstream): web upload submits the live form's fields (not stale hardcoded) 2026-05-28 22:28:24 +02:00
file-probe.test.js fix(rotation): suspect byse rejections now reach every account instead of dying on the first 2026-06-15 01:11:37 +02:00
history-retention.test.js feat(history): configurable retention + render cap so the Verlauf tab loads fast 2026-06-15 00:26:20 +02:00
hosters.test.js fix(hosters): defensive null-payload guards in result parsers + 7 tests 2026-04-28 10:12:32 +02:00
log-mode.test.js fix(log): persist BARE log path (no compounded daily/session stamps) 2026-06-04 22:08:15 +02:00
log-policy.test.js feat(log): per-hoster toggle for writing links to fileuploader.log 2026-05-23 15:29:25 +02:00
log-rotation.test.js test(log): extract log-rotation into testable module + 10 unit tests 2026-04-28 05:10:53 +02:00
queue-dedup.test.js fix(queue): stop auto-dedup from deleting pending jobs on restart/update 2026-05-25 01:08:59 +02:00
queue-prune.test.js test(queue): extract terminal-job prune into testable module + 10 tests 2026-04-28 06:41:47 +02:00
remote-config.test.js feat(remote): add remote control defaults to config store 2026-03-12 06:54:46 +01:00
remote-server.test.js feat(remote): add WebSocket server with auth, signaling relay, and rate limiting 2026-03-12 06:54:51 +01:00
semaphore.test.js test: add edge case tests for throttle and semaphore 2026-03-21 15:16:49 +01:00
stats.test.js feat(ui): per-hoster success rate, session-paused badge, post-batch retry, link export formats 2026-06-07 20:32:35 +02:00
support-bundle.test.js feat(diagnostics): log levels, support bundle export, verbose toggle, log paths panel 2026-06-07 16:34:51 +02:00
suspect-reject-alternates.test.js fix(byse): treat 5xx/gateway upload failures as transient infra, not account faults 2026-06-19 01:56:11 +02:00
throttle.test.js test: add edge case tests for throttle and semaphore 2026-03-21 15:16:49 +01:00
throttled-cache.test.js test(sort): extract throttled-cache utility + 12 unit tests 2026-04-28 07:12:52 +02:00
ui-smoke.js feat: improve account-driven uploads 2026-03-11 02:41:32 +01:00
upload-manager.test.js fix(byse): treat 5xx/gateway upload failures as transient infra, not account faults 2026-06-19 01:56:11 +02:00
validate-credentials.test.js fix(accounts): never persist unverified creds + dedupe-proof modal + label + perf 2026-06-07 03:11:13 +02:00
webhook-notify.test.js fix(webhook): retry+429+status handling, await before shutdown, error-path notify, abort/auto-retry suppress, Discord limits 2026-06-10 00:08:02 +02:00