{"record":{"id":"2ccbbc6473ab87ef","repo":"babalae/better-genshin-impact","slug":"ex-message","errorCode":null,"errorMessage":"读取文件失败: {ex.Message}","messagePattern":"读取文件失败: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Script/WebView/FileAccessBridge.cs","lineNumber":71,"sourceCode":"        }\n    }\n\n    public string ReadFile(string relativePath)\n    {\n        try\n        {\n            var fullPath = Path.Combine(_allowedDirectory, relativePath);\n            if (!IsPathAllowed(fullPath))\n                throw new UnauthorizedAccessException($\"访问路径 '{relativePath}' 被拒绝\");\n\n            if (!File.Exists(fullPath))\n                throw new FileNotFoundException($\"文件 '{relativePath}' 不存在\");\n\n            return File.ReadAllText(fullPath, Encoding.UTF8);\n        }\n        catch (Exception ex)\n        {\n            throw new Exception($\"读取文件失败: {ex.Message}\");\n        }\n    }\n\n    public void WriteFile(string relativePath, string content)\n    {\n        try\n        {\n            var fullPath = Path.Combine(_allowedDirectory, relativePath);\n            if (!IsPathAllowed(fullPath))\n                throw new UnauthorizedAccessException($\"访问路径 '{relativePath}' 被拒绝\");\n\n            // var directory = Path.GetDirectoryName(fullPath);\n            // if (!string.IsNullOrEmpty(directory))\n            //     Directory.CreateDirectory(directory);\n\n            File.WriteAllText(fullPath, content, new UTF8Encoding(false));\n        }\n        catch (Exception ex)","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Script/WebView/FileAccessBridge.cs#L53-L89","documentation":"Thrown by FileAccessBridge.ReadFile's catch-all: any exception inside ReadFile (UnauthorizedAccessException, FileNotFoundException, IOException, etc.) is wrapped and re-thrown as a generic Exception with prefix '读取文件失败: '. This destroys the original exception type and stack origin.","triggerScenarios":"Any exception in the try block of ReadFile — sandbox denial (135), missing file (136), IO error, encoding error, or File.ReadAllText failure — is caught by `catch (Exception ex)` and rewrapped.","commonSituations":"The underlying error is one of 135/136 or an IOException (locked file, disk error); the rewrap hides the original type so callers cannot distinguish UnauthorizedAccessException from FileNotFoundException.","solutions":["Remove the catch-all rewrap; let the specific exception (UnauthorizedAccessException, FileNotFoundException, IOException) propagate so callers can handle by type.","If a uniform exception type is required, use a custom exception type that preserves the original as InnerException and rethrow with ExceptionDispatchInfo.Capture(ex).Throw() to keep the stack.","At minimum, log the full exception before rewrapping."],"exampleFix":"// before\npublic string ReadFile(string relativePath)\n{\n    try { /* ... */ }\n    catch (Exception ex) { throw new Exception($\"读取文件失败: {ex.Message}\"); }\n}\n\n// after (let specific exceptions propagate; only wrap unexpected IO errors preserving InnerException)\npublic string ReadFile(string relativePath)\n{\n    var fullPath = Path.Combine(_allowedDirectory, relativePath);\n    if (!IsPathAllowed(fullPath)) throw new UnauthorizedAccessException($\"访问路径 '{relativePath}' 被拒绝\");\n    if (!File.Exists(fullPath)) throw new FileNotFoundException($\"文件 '{relativePath}' 不存在\", fullPath);\n    return File.ReadAllText(fullPath, Encoding.UTF8); // IOException propagates as-is\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Remove the catch-all; let specific exceptions propagate:\n// - UnauthorizedAccessException (sandbox)\n// - FileNotFoundException (missing)\n// - IOException (locked/disk)\n// If you must wrap, preserve InnerException:\ncatch (Exception ex)\n{\n    throw new FileAccessBridgeException(\"读取文件失败\", ex);\n}","preventionTips":["Do not catch-all and rewrap — it destroys the original type and stack.","If uniformity is required, define a custom exception that carries InnerException.","Log the full exception before rewrapping if you must rewrap."],"tags":["exception-handling","anti-pattern","webview","filesystem","catch-all"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}