{"record":{"id":"9d4ea114c23ed919","repo":"babalae/better-genshin-impact","slug":"error-sending-serverchan-message-ex-message","errorCode":null,"errorMessage":"Error sending ServerChan message: {ex.Message}","messagePattern":"Error sending ServerChan message: (.+?)","errorType":"exception","errorClass":"NotifierException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Service/Notifier/ServerChanNotifier.cs","lineNumber":67,"sourceCode":"            var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);\n            request.Content = new StringContent(postData, Encoding.UTF8, \"application/x-www-form-urlencoded\");\n\n            // 发送请求\n            var response = await _httpClient.SendAsync(request);\n\n            // 检查响应状态\n            if (!response.IsSuccessStatusCode)\n            {\n                throw new NotifierException($\"ServerChan调用失败，状态码: {response.StatusCode}\");\n            }\n        }\n        catch (NotifierException)\n        {\n            throw;\n        }\n        catch (System.Exception ex)\n        {\n            throw new NotifierException($\"Error sending ServerChan message: {ex.Message}\");\n        }\n    }\n\n    /// <summary>\n    /// 根据sendKey格式获取正确的API URL\n    /// </summary>\n    private string GetServerChanApiUrl(string key)\n    {\n        // 判断sendkey是否以\"sctp\"开头并提取数字部分\n        if (key.StartsWith(\"sctp\"))\n        {\n            var match = Regex.Match(key, @\"^sctp(\\d+)t\");\n            if (match.Success)\n            {\n                var num = match.Groups[1].Value;\n                return $\"https://{num}.push.ft07.com/send/{key}.send\";\n            }\n            else","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Service/Notifier/ServerChanNotifier.cs#L49-L85","documentation":"Catch-all wrapper: any non-NotifierException inside SendAsync's try is re-wrapped. Importantly, this is also what surfaces the ArgumentException thrown by GetServerChanApiUrl for a malformed sctp key (error 531), because GetServerChanApiUrl is called inside the try at line 39 and the generic catch at line 65 swallows ArgumentException into this message.","triggerScenarios":"HttpRequestException (DNS/socket); JsonException; OR ArgumentException from a bad sctp key format (error 531 propagates as this 530 message, losing the specific 'Invalid key format' text).","commonSituations":"Network outage; the sctp SendKey is malformed so the user sees a generic 'Error sending ServerChan message' instead of the helpful format hint.","solutions":["Move GetServerChanApiUrl validation OUTSIDE the try (or validate key format at construction) so error 531 surfaces cleanly.","Preserve the inner exception.","Differentiate network (HttpRequestException) from argument (ArgumentException) catches."],"exampleFix":"// before\ntry\n{\n    string apiUrl = GetServerChanApiUrl(_sendKey);\n    ...\n}\ncatch (NotifierException) { throw; }\ncatch (System.Exception ex)\n{\n    throw new NotifierException($\"Error sending ServerChan message: {ex.Message}\");\n}\n\n// after — validate key format up front so ArgumentException is not swallowed\nstring apiUrl = GetServerChanApiUrl(_sendKey); // throws ArgumentException cleanly if malformed\ntry\n{\n    ...\n}\ncatch (NotifierException) { throw; }\ncatch (HttpRequestException ex)\n{\n    throw new NotifierException($\"ServerChan network error: {ex.Message}\", ex);\n}\ncatch (System.Exception ex)\n{\n    throw new NotifierException($\"Error sending ServerChan message: {ex.Message}\", ex);\n}","handlingStrategy":"try-catch","validationCode":"// Validate key format up front so ArgumentException is not swallowed by the generic catch.\nif (sendKey.StartsWith(\"sctp\") && !Regex.IsMatch(sendKey, @\"^sctp\\d+t\"))\n    throw new InvalidOperationException(\"sctp SendKey format is invalid.\");","typeGuard":null,"tryCatchPattern":"try { await serverChanNotifier.SendAsync(data); }\ncatch (NotifierException ex) when (ex.Message.StartsWith(\"Error sending ServerChan\"))\n{ /* could be network OR a malformed key swallowed — re-check key format separately */ }","preventionTips":["Move GetServerChanApiUrl out of the try-block so format errors surface clearly.","Separate HttpRequestException (network) from ArgumentException (config).","Preserve the inner exception."],"tags":["serverchan","catch-all","network","notifier","error-masking"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}