{"record":{"id":"8c61fd84e9829e50","repo":"egametang/ET","slug":"http-request-fail-link-substring-0-link-indexof","errorCode":null,"errorMessage":"http request fail: {link.Substring(0,link.IndexOf('?'))}\\n{e}","messagePattern":"http request fail: (.+?)\\\\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.loader/Scripts/Loader/Client/CoroutineHelper.cs","lineNumber":27,"sourceCode":"        // 有了这个方法，就可以直接await Unity的AsyncOperation了\n        public static async ETTask GetAwaiter(this AsyncOperation asyncOperation)\n        {\n            ETTask task = ETTask.Create(true);\n            asyncOperation.completed += _ => { task.SetResult(); };\n            await task;\n        }\n        \n        public static async ETTask<string> HttpGet(string link)\n        {\n            try\n            {\n                UnityWebRequest req = UnityWebRequest.Get(link);\n                await req.SendWebRequest();\n                return req.downloadHandler.text;\n            }\n            catch (Exception e)\n            {\n                throw new Exception($\"http request fail: {link.Substring(0,link.IndexOf('?'))}\\n{e}\");\n            }\n        }\n    }\n}","sourceCodeStart":9,"sourceCodeEnd":31,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.loader/Scripts/Loader/Client/CoroutineHelper.cs#L9-L31","documentation":"Thrown by CoroutineHelper.HttpGet when UnityWebRequest.SendWebRequest() raises (network error, HTTP failure, timeout). The catch wraps the original exception. WARNING: the catch message itself calls link.Substring(0, link.IndexOf('?')) — if the link contains NO '?', IndexOf returns -1 and Substring(0,-1) throws ArgumentOutOfRangeException, masking the real network error with a string-processing crash. If the link has no query string, the error handler itself fails.","triggerScenarios":"HttpGet is awaited and the request fails (no network, server down, DNS failure, HTTP error code). Additionally, if the link passed to HttpGet has no '?' character, the error-formatting line crashes inside the catch block with a different exception than intended.","commonSituations":"Backend/auth server unreachable during client startup; a URL built without a query string passed to HttpGet; a redirect or certificate error from UnityWebRequest; WebGL build hitting CORS.","solutions":["Fix the latent bug: guard the IndexOf result before Substring (use link.IndexOf('?') >= 0 ? link.Substring(0, link.IndexOf('?')) : link).","Validate the URL scheme/host before calling HttpGet and surface a clear error if unreachable.","Wrap the HttpGet call in a retry/timeout policy so transient network failures don't crash client startup."],"exampleFix":"// before\nthrow new Exception($\"http request fail: {link.Substring(0,link.IndexOf('?'))}\\n{e}\");\n\n// after — safe truncation\nint q = link.IndexOf('?');\nstring safeUrl = q >= 0 ? link.Substring(0, q) : link;\nthrow new Exception($\"http request fail: {safeUrl}\\n{e}\");","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"string text;\ntry { text = await CoroutineHelper.HttpGet(url); }\ncatch (Exception e) { Log.Error($\"HttpGet failed for {url}: {e.Message}\"); /* fallback */ return; }","preventionTips":["Fix the latent IndexOf('?') bug so links without a query string don't crash the error formatter.","Validate the URL (scheme, host) before calling HttpGet.","Add a timeout/retry policy around HttpGet for flaky networks."],"tags":["loader","client","network","http","unity","bug"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}