{"record":{"id":"56ea8d0247701837","repo":"Hmbown/CodeWhale","slug":"agent-profile-path-is-not-a-directory","errorCode":null,"errorMessage":"agent profile path {} is not a directory","messagePattern":"agent profile path (.+?) is not a directory","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/profile.rs","lineNumber":360,"sourceCode":"    let dir = dir.as_ref();\n    let mut profiles = Vec::new();\n    let mut seen = BTreeSet::new();\n    for path in agent_profile_paths(dir)? {\n        let profile = load_agent_profile_file(&path)?;\n        if !seen.insert(profile.id.to_ascii_lowercase()) {\n            bail!(\"duplicate agent profile id {}\", profile.id);\n        }\n        profiles.push(profile);\n    }\n    Ok(profiles)\n}\n\nfn agent_profile_paths(dir: &Path) -> Result<Vec<PathBuf>> {\n    if !dir.exists() {\n        return Ok(Vec::new());\n    }\n    if !dir.is_dir() {\n        bail!(\"agent profile path {} is not a directory\", dir.display());\n    }\n\n    let mut paths = std::fs::read_dir(dir)\n        .with_context(|| format!(\"reading agent profile dir {}\", dir.display()))?\n        .collect::<std::io::Result<Vec<_>>>()\n        .with_context(|| format!(\"reading agent profile entries in {}\", dir.display()))?\n        .into_iter()\n        .map(|entry| entry.path())\n        .filter(|path| path.extension().and_then(|value| value.to_str()) == Some(\"toml\"))\n        .collect::<Vec<_>>();\n    paths.sort();\n    Ok(paths)\n}\n\nfn load_agent_profile_identity_file(path: &Path) -> Result<AgentProfileIdentity> {\n    let raw = std::fs::read_to_string(path)\n        .with_context(|| format!(\"reading agent profile identity {}\", path.display()))?;\n    let parsed: AgentProfileIdentityToml = toml::from_str(&raw)","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/fleet/profile.rs#L342-L378","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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"],"exampleFix":"// before\nagent_profiles = \"/home/me/.codewhale/profiles/researcher.toml\"\n\n// after\nagent_profiles = \"/home/me/.codewhale/profiles\"","handlingStrategy":"validation","validationCode":"let meta = std::fs::metadata(path)?;\nif !meta.is_dir() {\n    eprintln!(\"{} is not a directory\", path.display());\n}","typeGuard":"fn is_existing_dir(p: &Path) -> bool {\n    p.is_dir()\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"is not a directory\") => {\n        eprintln!(\"check the agent_profiles path in config — it must be a directory\");\n    }\n    other => other?,\n}","preventionTips":["Point config at the profiles directory, never at an individual TOML file","After sync/backup restores, verify the profiles path is still a directory"],"tags":["fleet","agent-profiles","path","config"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}