Hmbown/CodeWhale · error
agent profile path is not a directory
Error message
agent profile path {} is not a directory What it means
agent_profile_paths validates that the agent profiles directory exists and is actually a directory before reading entries. If the path exists but is not a directory (e.g. a regular file or symlink to a file), the loader bails with this message rather than returning an IO error.
Solutions
- Fix the configured path to point at the profiles directory, not a file inside it
- Verify with `ls -la <path>` that the target is a directory (`d` in permissions)
- If you meant to load one profile file, place it in a directory and point config at the directory
- Recreate the directory if a tool replaced it with a file
Example fix
// before agent_profiles = "/home/me/.codewhale/profiles/researcher.toml" // after agent_profiles = "/home/me/.codewhale/profiles"
Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::metadata(path)?;
if !meta.is_dir() {
eprintln!("{} is not a directory", path.display());
} Type guard
fn is_existing_dir(p: &Path) -> bool {
p.is_dir()
} Try / catch
match result {
Err(e) if e.to_string().contains("is not a directory") => {
eprintln!("check the agent_profiles path in config — it must be a directory");
}
other => other?,
} Prevention
- Point config at the profiles directory, never at an individual TOML file
- After sync/backup restores, verify the profiles path is still a directory
When it happens
Trigger: Passing a file path (or a symlink to a file) as the agent profiles directory to load_agent_profiles_from_dir_tolerant / load_agent_profile_identities_from_dir / load_agent_profiles_from_dir; a path that exists via dir.exists() but fails dir.is_dir().
Common situations: Config pointing `agent_profiles` at a single TOML file instead of its containing directory; a miswritten path in config (missing a directory component); the directory being replaced by a file by a sync/backup tool.
Related errors
- agent profile tools.posture= would widen permissions; use…
- duplicate agent profile id
- agent profile cannot be empty
- agent profile must be a simple token
- agent profile may not disable approval_required
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/56ea8d0247701837.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/profile.rs:360
let dir = dir.as_ref();
let mut profiles = Vec::new();
let mut seen = BTreeSet::new();
for path in agent_profile_paths(dir)? {
let profile = load_agent_profile_file(&path)?;
if !seen.insert(profile.id.to_ascii_lowercase()) {
bail!("duplicate agent profile id {}", profile.id);
}
profiles.push(profile);
}
Ok(profiles)
}
fn agent_profile_paths(dir: &Path) -> Result<Vec<PathBuf>> {
if !dir.exists() {
return Ok(Vec::new());
}
if !dir.is_dir() {
bail!("agent profile path {} is not a directory", dir.display());
}
let mut paths = std::fs::read_dir(dir)
.with_context(|| format!("reading agent profile dir {}", dir.display()))?
.collect::<std::io::Result<Vec<_>>>()
.with_context(|| format!("reading agent profile entries in {}", dir.display()))?
.into_iter()
.map(|entry| entry.path())
.filter(|path| path.extension().and_then(|value| value.to_str()) == Some("toml"))
.collect::<Vec<_>>();
paths.sort();
Ok(paths)
}
fn load_agent_profile_identity_file(path: &Path) -> Result<AgentProfileIdentity> {
let raw = std::fs::read_to_string(path)
.with_context(|| format!("reading agent profile identity {}", path.display()))?;
let parsed: AgentProfileIdentityToml = toml::from_str(&raw)View on GitHub (pinned to 73e0f67d83)