babalae/better-genshin-impact · error · Exception

写入文件失败: {ex.Message}

Error message

写入文件失败: {ex.Message}

What it means

Thrown by FileAccessBridge.WriteFile's catch-all: any exception (UnauthorizedAccessException from 138, IOException from a locked/read-only target, disk-full, etc.) is rewrapped as a generic Exception with prefix '写入文件失败: '. Same anti-pattern as error 137 on the write path.

Source

Thrown at BetterGenshinImpact/Core/Script/WebView/FileAccessBridge.cs:91

    }

    public void WriteFile(string relativePath, string content)
    {
        try
        {
            var fullPath = Path.Combine(_allowedDirectory, relativePath);
            if (!IsPathAllowed(fullPath))
                throw new UnauthorizedAccessException($"访问路径 '{relativePath}' 被拒绝");

            // var directory = Path.GetDirectoryName(fullPath);
            // if (!string.IsNullOrEmpty(directory))
            //     Directory.CreateDirectory(directory);

            File.WriteAllText(fullPath, content, new UTF8Encoding(false));
        }
        catch (Exception ex)
        {
            throw new Exception($"写入文件失败: {ex.Message}");
        }
    }

    public bool FileExists(string relativePath)
    {
        try
        {
            var fullPath = Path.Combine(_allowedDirectory, relativePath);
            if (!IsPathAllowed(fullPath))
                return false;

            return File.Exists(fullPath);
        }
        catch
        {
            return false;
        }
    }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Remove the catch-all rewrap; let UnauthorizedAccessException and IOException propagate with their original types.
  2. Uncomment the Directory.CreateDirectory block (lines 83-85) so writing to a not-yet-existing subdirectory doesn't fail — but only after confirming the path passed IsPathAllowed.
  3. If a uniform type is needed, preserve InnerException and use ExceptionDispatchInfo to keep the stack.

Example fix

// before
public void WriteFile(string relativePath, string content)
{
    try
    {
        var fullPath = Path.Combine(_allowedDirectory, relativePath);
        if (!IsPathAllowed(fullPath)) throw new UnauthorizedAccessException($"访问路径 '{relativePath}' 被拒绝");
        File.WriteAllText(fullPath, content, new UTF8Encoding(false));
    }
    catch (Exception ex) { throw new Exception($"写入文件失败: {ex.Message}"); }
}

// after (no rewrap; create parent dir if needed after sandbox check)
public void WriteFile(string relativePath, string content)
{
    var fullPath = Path.Combine(_allowedDirectory, relativePath);
    if (!IsPathAllowed(fullPath)) throw new UnauthorizedAccessException($"访问路径 '{relativePath}' 被拒绝");
    var dir = Path.GetDirectoryName(fullPath);
    if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
    File.WriteAllText(fullPath, content, new UTF8Encoding(false));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure parent dir exists (currently commented out) after the sandbox check passes
var dir = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);

Try / catch

// Remove the catch-all; let UnauthorizedAccessException / IOException propagate.
// If wrapping is unavoidable:
catch (Exception ex)
{
    throw new FileAccessBridgeException("写入文件失败", ex);
}

Prevention

When it happens

Trigger: Any exception in WriteFile's try block is caught by `catch (Exception ex)` and re-thrown as new Exception("写入文件失败: " + ex.Message), losing the original type.

Common situations: Underlying cause is sandbox denial (138), file is read-only/locked, destination directory missing (note: directory creation is commented out on lines 83-85!), or disk full. The rewrap hides which occurred.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/a404584d9ca6e6ea. Report an issue: GitHub.