{"record":{"id":"619c4a0691f24fc7","repo":"BigPizzaV3/CodexPlusPlus","slug":"skills-619c4a","errorCode":null,"errorMessage":"仓库压缩包太大：{} 字节","messagePattern":"仓库压缩包太大：(.+?) 字节","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/skills.rs","lineNumber":978,"sourceCode":"    let client = github_client()?;\n    let response = with_github_auth(client.get(repo_zip_url(repo)))\n        .header(reqwest::header::ACCEPT, \"application/zip\")\n        .send()\n        .await\n        .with_context(|| format!(\"下载 {}/{} 失败\", repo.owner, repo.name))?;\n    let status = response.status();\n    if !status.is_success() {\n        anyhow::bail!(\n            \"下载 {}/{} 失败：HTTP {}{}\",\n            repo.owner,\n            repo.name,\n            status.as_u16(),\n            github_status_hint(status.as_u16())\n        );\n    }\n    let bytes = response.bytes().await.context(\"读取仓库压缩包内容失败\")?;\n    if bytes.len() > REPO_ZIP_DOWNLOAD_LIMIT_BYTES {\n        anyhow::bail!(\"仓库压缩包太大：{} 字节\", bytes.len());\n    }\n    Ok(bytes.to_vec())\n}\n\n/// 软链优先，失败回退复制。Windows 上建目录软链要开发者模式或管理员权限，\n/// 拿不到就退化成复制——功能一样，只是更新时要重装。\nfn link_or_copy(source: &Path, link: &Path) -> anyhow::Result<()> {\n    if symlink_dir(source, link).is_ok() {\n        return Ok(());\n    }\n    copy_dir_all(source, link)\n        .with_context(|| format!(\"复制 skill 到 {} 失败（软链也没建成）\", link.display()))\n}\n\n#[cfg(unix)]\nfn symlink_dir(source: &Path, link: &Path) -> std::io::Result<()> {\n    std::os::unix::fs::symlink(source, link)\n}","sourceCodeStart":960,"sourceCodeEnd":996,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/skills.rs#L960-L996","documentation":"After download_repo_zip reads the response bytes, it enforces a size ceiling (a few MB) and bails when the archive exceeds it. This prevents unbounded memory use when someone registers a huge repository as a skill source.","triggerScenarios":"目标仓库的 zip 包体积超过 REPO_ZIP_DOWNLOAD_LIMIT_BYTES（下载包含大量历史资产或大二进制文件的仓库时）。","commonSituations":"误把含模型权重、视频或数据集的大仓库当作技能仓库安装；上游仓库膨胀后首次超过阈值；limits 常量配置过小。","solutions":["改用更小/仅含技能目录的仓库或子目录打包","评估并按需调大 REPO_ZIP_DOWNLOAD_LIMIT_BYTES 常量","改为流式下载落盘再解压，避免一次性读入内存（代码改造）"],"exampleFix":"// before\nif bytes.len() > REPO_ZIP_DOWNLOAD_LIMIT_BYTES {\n    anyhow::bail!(\"仓库压缩包太大：{} 字节\", bytes.len());\n}\n// after\nif bytes.len() > REPO_ZIP_DOWNLOAD_LIMIT_BYTES {\n    anyhow::bail!(\n        \"仓库压缩包太大：{} 字节（上限 {} 字节）\",\n        bytes.len(),\n        REPO_ZIP_DOWNLOAD_LIMIT_BYTES\n    );\n}","handlingStrategy":"validation","validationCode":"// 调用前用 HEAD 请求预检体积\nlet size: Option<u64> = client.head(&url).send().await.ok()\n    .and_then(|r| r.headers().get(reqwest::header::CONTENT_LENGTH)?.to_str().ok()?.parse().ok());\nif size.map(|s| s > REPO_ZIP_DOWNLOAD_LIMIT_BYTES).unwrap_or(false) {\n    eprintln!(\"仓库 zip 预计超过大小上限，已跳过\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"match download_repo_zip(&repo).await {\n    Err(e) if e.to_string().contains(\"压缩包太大\") => {\n        eprintln!(\"仓库过大，请改用子目录打包或联系维护者调整上限\");\n    }\n    other => other?,\n}","preventionTips":["不要把含大文件（模型、数据集）的仓库当技能仓库","安装前在 GitHub 网页查看仓库体积","技能仓库保持精简，用 .gitignore 排除大文件"],"tags":["zip","download","size-limit","memory"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}