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
- 在调用 upsert_repo 前确保 owner 和 name 均为非空字符串(trim 后)
- 若从 GitHub URL 推导,检查 URL 解析逻辑是否正确提取了 owner/repo 两段
- 前端在提交前做必填校验,禁用空 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
- 表单层对 owner/name 做必填校验后再提交
- 从 GitHub URL 解析 owner/name 时对解析结果做断言
- 反序列化 SkillRepo 配置后校验关键字段非空
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)