{"record":{"id":"b5a34e82248e57cd","repo":"Hmbown/CodeWhale","slug":"sub-agent-transcript-artifact-is-not-a-regular-fil","errorCode":null,"errorMessage":"sub-agent transcript artifact is not a regular file: {}","messagePattern":"sub-agent transcript artifact is not a regular file: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":8609,"sourceCode":"                .cloned()\n                .ok_or_else(|| anyhow!(\"sub-agent transcript record is missing its message\"))?,\n        )?;\n        messages.push(message);\n    }\n    Ok(messages)\n}\n\nfn remove_subagent_transcript_artifact(state_root: &Path, agent_id: &str) -> Result<bool> {\n    let state_root = normalize_subagent_workspace(state_root);\n    let path = checked_subagent_transcript_artifact_path(&state_root, agent_id)?;\n    reject_root_relative_symlinks(&state_root, &path)?;\n    let metadata = match fs::symlink_metadata(&path) {\n        Ok(metadata) => metadata,\n        Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(false),\n        Err(err) => return Err(err.into()),\n    };\n    if metadata.file_type().is_symlink() || !metadata.file_type().is_file() {\n        return Err(anyhow!(\n            \"sub-agent transcript artifact is not a regular file: {}\",\n            path.display()\n        ));\n    }\n    fs::remove_file(path)?;\n    Ok(true)\n}\n\n#[cfg(test)]\npub(crate) fn write_subagent_transcript_artifact_for_test(\n    state_root: &Path,\n    agent_id: &str,\n    messages: &[Message],\n) -> Result<PathBuf> {\n    let mut writer = SubAgentTranscriptArtifactWriter::create(state_root, agent_id)?;\n    writer.sync_messages(messages, true)?;\n    Ok(writer.path)\n}","sourceCodeStart":8591,"sourceCodeEnd":8627,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/mod.rs#L8591-L8627","documentation":"Before deleting a sub-agent transcript artifact, the code checks it with `fs::symlink_metadata` and requires the entry to be a regular file — not a symlink, directory, FIFO, or other special file. If the path exists but is not a plain file, deletion is refused to avoid following or clobbering unexpected filesystem objects.","triggerScenarios":"Attempting transcript cleanup on a path that resolves to a symlink or a directory instead of a regular file; the check `metadata.file_type().is_symlink() || !metadata.file_type().is_file()` fires.","commonSituations":"A user replaced the transcript file with a symlink to shared storage; a directory was created where the artifact should live; tmpfs or container volume mounts produced non-regular entries.","solutions":["Remove the symlink or directory at that path manually and let the library recreate a regular file.","Point the sub-agent state root at a location where the artifact path is a plain file.","If the symlink is intentional, copy the target's contents into a regular file at the artifact path first.","Check that container/volume mounts are not substituting special file types at the state path."],"exampleFix":"// before: transcript path is a symlink\nls -l ~/.codewhale/state/transcripts/abc.jsonl  # -> symlink\n// after: replace with a regular file\nrm ~/.codewhale/state/transcripts/abc.jsonl\ncp /shared/abc.jsonl ~/.codewhale/state/transcripts/abc.jsonl","handlingStrategy":"validation","validationCode":"use std::fs;\nfn is_regular_file(p: &std::path::Path) -> bool {\n    fs::symlink_metadata(p).map(|m| m.file_type().is_file()).unwrap_or(false)\n}\n// only call the delete/cleanup API when is_regular_file(path)","typeGuard":null,"tryCatchPattern":"match cleanup_transcript(path) {\n    Ok(removed) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"not a regular file\") => {\n        // remove the symlink/dir yourself, then retry\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Do not symlink transcript artifacts into shared storage.","Keep the state root free of directories/special files at artifact paths.","Audit container volume mounts for substituted file types."],"tags":["subagent","filesystem","symlink","validation"],"backgroundTag":"incompatible-source-type","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"}