BigPizzaV3/CodexPlusPlus · error · anyhow::Error

仓库 owner 和 name 不能为空

Error message

仓库 owner 和 name 不能为空

What it means

normalize_repo trims the SkillRepo fields and rejects the result when owner or name is empty after trimming. Whitespace-only input is the typical trigger; without owner/name the GitHub tree/zip URLs cannot be constructed, so upsert_repo fails fast.

Solutions

  1. 在调用 upsert_repo 前确保 owner 和 name 均为非空字符串(trim 后)
  2. 若从 GitHub URL 推导,检查 URL 解析逻辑是否正确提取了 owner/repo 两段
  3. 前端在提交前做必填校验,禁用空 owner/name 的提交按钮

Example fix

// before
state.upsert_repo(&SkillRepo { owner: "".into(), name: repo_name, ..Default::default() })?;
// after
if owner.trim().is_empty() || name.trim().is_empty() {
    return Err(anyhow!("owner/name 必填"));
}
state.upsert_repo(&SkillRepo { owner: owner.into(), name: name.into(), ..Default::default() })?;
Defensive patterns

Strategy: validation

Validate before calling

fn repo_fields_filled(owner: &str, name: &str) -> bool {
    !owner.trim().is_empty() && !name.trim().is_empty()
}

Try / catch

match state.upsert_repo(&repo) {
    Err(e) if e.to_string().contains("不能为空") => eprintln!("owner/name 为必填字段,请补全后重试"),
    other => other?,
}

Prevention

When it happens

Trigger: 调用 upsert_repo 传入的 SkillRepo 中 owner 或 name 字段为空字符串或仅含空白字符(trim 后为空)。

Common situations: 前端表单未填写完整就提交;从 GitHub URL 解析 owner/name 失败后得到空串;配置文件迁移时字段缺失被反序列化为空 String;默认占位值未替换。

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/e2593b192be3368d. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/skills.rs:598

        subdir,
        enabled: true,
    })
}

fn normalize_repo(repo: SkillRepo) -> anyhow::Result<SkillRepo> {
    let owner = repo.owner.trim().to_string();
    let name = repo.name.trim().to_string();
    let branch = {
        let trimmed = repo.branch.trim();
        if trimmed.is_empty() {
            default_branch()
        } else {
            trimmed.to_string()
        }
    };
    let subdir = repo.subdir.trim().trim_matches('/').to_string();
    if owner.is_empty() || name.is_empty() {
        anyhow::bail!("仓库 owner 和 name 不能为空");
    }
    if !is_safe_repo_segment(&owner) || !is_safe_repo_segment(&name) {
        anyhow::bail!("仓库 owner/name 只能包含字母、数字、`.`、`_`、`-`");
    }
    Ok(SkillRepo {
        owner,
        name,
        branch,
        subdir,
        enabled: repo.enabled,
    })
}

fn is_safe_repo_segment(value: &str) -> bool {
    !value.is_empty()
        && value
            .chars()
            .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-'))

View on GitHub (pinned to b1ed92e5e4)