jlcodes99/cockpit-tools · error

读取文件失败 {:?}: {}

Error message

读取文件失败 {:?}: {}

What it means

In import_from_files(), each selected path is read with fs::read_to_string(path); on failure the OS error is logged as '读取文件失败 {:?}: {}' and the file is skipped (continue). This is std::fs I/O failing before any parsing, so the file contributes no import candidate.

Source

Thrown at src-tauri/src/modules/codex_account_mutations_quota.rs:27

    }
    ensure_storage_writable_for_import()?;

    logger::log_info(&format!(
        "Codex: 开始从 {} 个文件导入账号...",
        file_paths.len()
    ));

    // 原有文件导入候选: (CodexTokens, account_id_hint, label, auth_file_plan_type)
    let mut candidates: Vec<(CodexTokens, Option<String>, String, Option<String>)> = Vec::new();
    // 旧规则未识别到账号时,才用 Token/JSON 粘贴框的解析逻辑处理整个文件内容。
    let mut fallback_files: Vec<(String, String, Option<String>)> = Vec::new();

    for file_path in &file_paths {
        let path = Path::new(file_path);
        let content = match fs::read_to_string(path) {
            Ok(c) => c,
            Err(e) => {
                logger::log_error(&format!("读取文件失败 {:?}: {}", file_path, e));
                continue;
            }
        };

        // 从文件名推断 email 作为 label
        let filename_label = path
            .file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown")
            .to_string();
        let auth_file_plan_type = detect_auth_file_plan_type_from_path(path);

        let parsed: serde_json::Value = match serde_json::from_str(&content) {
            Ok(v) => v,
            Err(e) => {
                logger::log_warn(&format!(
                    "Codex 文件旧规则 JSON 解析失败,将尝试 Token/JSON 导入逻辑 {:?}: {}",
                    file_path, e

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Read the logged OS error kind to distinguish NotFound / PermissionDenied / InvalidData and address it (correct path, chmod, re-download).
  2. Verify the file exists and is readable before importing (ls -l / open in an editor).
  3. For invalid UTF-8, convert the auth file encoding to UTF-8, or read bytes and lossy-convert before parsing.
  4. For cloud placeholders, force-download the file (e.g. 'Always keep on this device' in OneDrive) before import.

Example fix

// before
let content = match fs::read_to_string(path) {
    Ok(c) => c,
    Err(e) => { logger::log_error(&format!("读取文件失败 {:?}: {}", file_path, e)); continue; }
};
// after
let content = match fs::read(path).and_then(|b| String::from_utf8(b).map_err(|e| e.into())) {
    Ok(c) => c,
    Err(e) => { logger::log_error(&format!("读取文件失败 {:?}: {}", file_path, e)); continue; }
};
Defensive patterns

Strategy: validation

Validate before calling

// Before calling import_from_files, filter paths the caller can read:
use std::path::Path;
let readable: Vec<&String> = file_paths.iter()
    .filter(|p| Path::new(p).is_file())
    .collect();

Try / catch

// The library already skips unreadable files; on the caller side treat the logged per-file
// error as non-fatal and report which paths failed:
for failed_path in unreadable { eprintln!("skipped: {failed_path}"); }

Prevention

When it happens

Trigger: fs::read_to_string returns Err: path does not exist, permission denied, path is a directory, file contains invalid UTF-8, or the file vanished between selection and read.

Common situations: User selects files on a disconnected/removable drive, picks non-UTF-8 or binary files, lacks read permission (e.g. another user's home dir), cloud-placeholder files not downloaded, or non-ASCII paths mangled by the file picker.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/4c8ae34ea0346988. Report an issue: GitHub.