{"record":{"id":"11fbec58e4eb0d45","repo":"netchx/netch","slug":"item-remark-response-status-code-code","errorCode":null,"errorMessage":"{item.Remark} Response Status Code: {code}","messagePattern":"(.+?) Response Status Code: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"Netch/Utils/SubscriptionUtil.cs","lineNumber":36,"sourceCode":"        {\n            if (!item.Enable)\n                return;\n\n            var request = WebUtil.CreateRequest(item.Link);\n\n            if (!string.IsNullOrEmpty(item.UserAgent))\n                request.UserAgent = item.UserAgent;\n\n            if (!string.IsNullOrEmpty(proxyServer))\n                request.Proxy = new WebProxy(proxyServer);\n\n            List<Server> servers;\n\n            var (code, result) = await WebUtil.DownloadStringAsync(request);\n            if (code == HttpStatusCode.OK)\n                servers = ShareLink.ParseText(result);\n            else\n                throw new Exception($\"{item.Remark} Response Status Code: {code}\");\n\n            foreach (var server in servers)\n                server.Group = item.Remark;\n\n            lock (ServerLock)\n            {\n                Global.Settings.Server.RemoveAll(server => server.Group.Equals(item.Remark));\n                Global.Settings.Server.AddRange(servers);\n            }\n\n            Global.MainForm.NotifyTip(i18N.TranslateFormat(\"Update {1} server(s) from {0}\", item.Remark, servers.Count));\n        }\n        catch (Exception e)\n        {\n            Global.MainForm.NotifyTip($\"{i18N.TranslateFormat(\"Update servers failed from {0}\", item.Remark)}\\n{e.Message}\", info: false);\n            Log.Warning(e, \"Update servers failed\");\n        }\n    }","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/netchx/netch/blob/9d99eb1c5a2acbf2a34f2600f94242601019a300/Netch/Utils/SubscriptionUtil.cs#L18-L54","documentation":"During subscription update, UpdateServerCoreAsync issues the HTTP request and throws if the status is anything other than 200 OK, embedding the subscription Remark and the returned HttpStatusCode. The exception is caught by the surrounding try/catch in the same method: it shows a NotifyTip and logs a warning, so the application continues and other subscriptions still update (UpdateServersAsync uses Task.WhenAll per item). Non-200 covers auth failures (401/403), not-found (404), server errors (5xx), and rate-limiting (429).","triggerScenarios":"Subscription URL returns non-200: expired/changed link (404), token required (401/403), upstream server error (500/502/503), rate limit (429), or a CDN/Cloudflare challenge page. A redirect to an HTML error page can also surface here.","commonSituations":"Subscription provider rotated the URL; auth token expired; temporary provider outage; Cloudflare WAF blocking Netch's default User-Agent; provider returning HTML on error instead of server links.","solutions":["Open the subscription URL in a browser to confirm what it returns.","Update the subscription Link in settings to the current URL.","If auth is required, append the token/parameter the provider documents.","For 429/5xx, retry after a short delay (transient).","Set a realistic item.UserAgent if the provider blocks the default client."],"exampleFix":"// before\nif (code == HttpStatusCode.OK)\n    servers = ShareLink.ParseText(result);\nelse\n    throw new Exception($\"{item.Remark} Response Status Code: {code}\");\n// after - distinguish transient from permanent status codes\nif (code == HttpStatusCode.OK)\n    servers = ShareLink.ParseText(result);\nelse if (code == HttpStatusCode.TooManyRequests || (int)code >= 500)\n    throw new TransientSubscriptionException($\"{item.Remark} transient {code}\");\nelse\n    throw new SubscriptionException($\"{item.Remark} permanent {code}\");","handlingStrategy":"retry","validationCode":"// Pre-check reachability and surface a clear message before the bulk update\nvar (code, _) = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(item.Link));\nif (code != HttpStatusCode.OK)\n    Global.MainForm.NotifyTip($\"{item.Remark} returned {code}; check the subscription link.\");","typeGuard":null,"tryCatchPattern":"int attempt = 0;\nRetry:\ntry { await UpdateServerCoreAsync(item, proxyServer); }\ncatch (Exception ex) when (attempt++ < 3 && (ex.Message.Contains(\"429\") || ex.Message.Contains(\"50\")))\n{\n    await Task.Delay(TimeSpan.FromSeconds(5 * attempt));\n    goto Retry;\n}\ncatch (Exception e)\n{\n    Global.MainForm.NotifyTip($\"Update servers failed from {item.Remark}\\n{e.Message}\", info: false);\n    Log.Warning(e, \"Update servers failed\");\n}","preventionTips":["Distinguish transient (5xx/429) from permanent (4xx) status codes; only retry transient ones.","Set item.UserAgent to a browser-like value if the provider blocks default clients.","Validate the subscription Link is reachable on add/edit with a quick HEAD request.","Surface the specific status code to the user (already done) so they can act.","Keep updates per-item so one failing subscription does not block others (UpdateServersAsync already uses Task.WhenAll per item)."],"tags":["subscription","http","network","status-code"],"backgroundTag":null,"analyzedSha":"9d99eb1c5a2acbf2a34f2600f94242601019a300","analyzedAt":"2026-08-13T14:12:19.105Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}