jlcodes99/cockpit-tools · error

未找到有效 Token

Error message

未找到有效 Token {:?}

What it means

During import_from_files, a JSON file parsed as a top-level object was inspected by extract_codex_tokens_from_value, which looks for known Codex token fields (accessToken/access_token, id_token + access_token, or refresh_token). When none of these token keys are found in the object, this error is logged and the file falls back to the Token/JSON import logic. It means the file is valid JSON but lacks the credential fields the importer recognizes.

Solutions

  1. Open the file and confirm it contains at least one of accessToken/access_token, id_token+access_token, or refresh_token
  2. Re-authenticate with the Codex CLI so auth.json is regenerated with valid tokens
  3. Verify you are importing the auth file, not a config or settings file
  4. Check for renamed key casing (accessToken vs access_token) depending on CLI version

Example fix

// before (auth.json)
{ "OPENAI_API_KEY": "sk-..." }
// after
{ "tokens": { "id_token": "...", "access_token": "...", "refresh_token": "..." } }
Defensive patterns

Strategy: validation

Validate before calling

fn has_codex_tokens(v: &serde_json::Value) -> bool {
    let obj = match v { serde_json::Value::Object(o) => o, _ => return false };
    obj.contains_key("accessToken") || obj.contains_key("access_token")
        || obj.contains_key("refresh_token")
        || (obj.contains_key("id_token") && obj.contains_key("access_token"))
}
// call before import: if !has_codex_tokens(&parsed) { fix file first }

Type guard

fn is_json_object(v: &serde_json::Value) -> bool {
    matches!(v, serde_json::Value::Object(_))
}

Prevention

When it happens

Trigger: Calling import_from_files with a JSON file whose top-level is an object but which contains none of accessToken, access_token, id_token+access_token, or refresh_token — e.g. an auth.json that only has OPENAI_API_KEY, or a config/settings JSON dropped in by mistake.

Common situations: Users hand-edit auth.json and delete the tokens; importing a Codex config.json or settings file instead of auth.json; provider version changes renamed token fields; copying an empty or partially-written auth file.

Related errors


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

Appendix: source

Thrown at crates/cockpit-core/src/modules/codex_account_core_mutations_quota.rs:57

        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
                ));
                fallback_files.push((content, filename_label));
                continue;
            }
        };

        let before_count = candidates.len();
        match &parsed {
            serde_json::Value::Object(_) => {
                if let Some((tokens, hint)) = extract_codex_tokens_from_value(&parsed) {
                    candidates.push((tokens, hint, filename_label.clone()));
                } else {
                    logger::log_error(&format!("未找到有效 Token {:?}", file_path));
                }
            }
            serde_json::Value::Array(arr) => {
                for item in arr {
                    if let Some((tokens, hint)) = extract_codex_tokens_from_value(item) {
                        let label = item
                            .get("email")
                            .and_then(|v| v.as_str())
                            .unwrap_or(&filename_label)
                            .to_string();
                        candidates.push((tokens, hint, label));
                    }
                }
            }
            _ => {
                logger::log_error(&format!("不支持的 JSON 格式 {:?}", file_path));
            }
        }

View on GitHub (pinned to 1ed8b77992)