BigPizzaV3/CodexPlusPlus · error · anyhow::Error
skill 源目录不存在:
Error message
skill 源目录不存在:{} What it means
set_enabled materializes a skill into the linked directory by creating a symlink/copy from the skill's source directory. If the expected source directory (source_dir joined with the skill id) does not exist or is not a directory, enabling is aborted with this message.
Solutions
- Verify the skill directory exists at <source_dir>/<id> and re-add it if deleted
- Check the configured skills source directory path in settings points to the right root
- Reinstall the skill (install_from_zip or manual copy) before enabling it
- Confirm the skill id casing matches the on-disk directory name exactly
Example fix
// before
skills.set_enabled("my-skill", true)?; // 源目录已删
// after
let src = skills_root.join("my-skill");
if !src.is_dir() {
// 重新安装或修正 skills 根目录后再启用
anyhow::bail!("请先安装 skill my-skill 到 {}", skills_root.display());
}
skills.set_enabled("my-skill", true)?; Defensive patterns
Strategy: validation
Validate before calling
let src = skills_root.join(id);
if !src.is_dir() {
anyhow::bail!("skill 源目录不存在:{}", src.display());
} Type guard
fn skill_source_exists(skills_root: &Path, id: &str) -> bool {
skills_root.join(id).is_dir()
} Try / catch
match skills.set_enabled(id, true) {
Err(e) if e.to_string().starts_with("skill 源目录不存在") => eprintln!("请先重新安装该 skill"),
other => other?,
} Prevention
- 启用前确认 <source_dir>/<id> 存在
- 删除 skill 时同步清理注册状态
- 校验 skills 根目录配置
- zip 安装后核对目录名与 id 大小写一致
When it happens
Trigger: Calling set_enabled(id, true) (directly or via install_from_zip / restore_backup) when self.source_dir.join(id) is missing or is a file, not a directory.
Common situations: Skill was deleted from the source dir while still registered; a wrong skills root directory is configured; a zip install was cleaned up or a backup restore references a removed path; case-mismatched skill id on a case-sensitive filesystem.
Related errors
- Codex CLI 路径指向的是目录而不是可执行文件:
- Codex CLI 没有执行权限:
- Codex CLI 路径不存在: 请填 Codex CLI 可执行文件的完整路径。macOS 桌面版通常在…
- 拒绝删除文件系统根目录:
- 拒绝递归删除 CODEX_HOME 本身(
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/5c4e614bf6661cb0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/skills.rs:442
},
);
self.save_state_unlocked(&state)?;
drop(_guard);
self.set_enabled(&skill.id, true)?;
Ok(self.load_state())
}
/// 启用 = 在 `$CODEX_HOME/skills/` 下建一个指向源目录的软链;停用 = 删掉它。
pub fn set_enabled(&self, id: &str, enabled: bool) -> anyhow::Result<()> {
validate_skill_id(id)?;
let source = self.source_dir.join(id);
let link = self.linked_dir().join(id);
if !enabled {
return remove_link(&link);
}
if !source.is_dir() {
anyhow::bail!("skill 源目录不存在:{}", source.display());
}
std::fs::create_dir_all(self.linked_dir())
.with_context(|| format!("创建 {} 失败", self.linked_dir().display()))?;
remove_link(&link)?;
link_or_copy(&source, &link)
}
/// 卸载:删软链,源目录整体移进备份目录。不做自动轮转删除。
pub fn uninstall(&self, id: &str) -> anyhow::Result<SkillsState> {
validate_skill_id(id)?;
remove_link(&self.linked_dir().join(id))?;
let source = self.source_dir.join(id);
if source.is_dir() {
std::fs::create_dir_all(&self.backups_dir)
.with_context(|| format!("创建备份目录失败:{}", self.backups_dir.display()))?;
let backup = self
.backups_dirView on GitHub (pinned to b1ed92e5e4)