Hmbown/CodeWhale · error
sub-agent transcript artifact is not a regular file: {}
Error message
sub-agent transcript artifact is not a regular file: {} What it means
`remove_subagent_transcript_artifact` lstats the artifact path via symlink_metadata and refuses to unlink when it is a symlink or not a regular file. This prevents cleanup from following a link out of the sub-agent state root or deleting special files, so a tampered path fails closed instead of erasing something else.
Source
Thrown at crates/tui/src/tools/subagent/mod.rs:7638
.cloned()
.ok_or_else(|| anyhow!("sub-agent transcript record is missing its message"))?,
)?;
messages.push(message);
}
Ok(messages)
}
fn remove_subagent_transcript_artifact(state_root: &Path, agent_id: &str) -> Result<bool> {
let state_root = normalize_subagent_workspace(state_root);
let path = checked_subagent_transcript_artifact_path(&state_root, agent_id)?;
reject_root_relative_symlinks(&state_root, &path)?;
let metadata = match fs::symlink_metadata(&path) {
Ok(metadata) => metadata,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(false),
Err(err) => return Err(err.into()),
};
if metadata.file_type().is_symlink() || !metadata.file_type().is_file() {
return Err(anyhow!(
"sub-agent transcript artifact is not a regular file: {}",
path.display()
));
}
fs::remove_file(path)?;
Ok(true)
}
#[cfg(test)]
pub(crate) fn write_subagent_transcript_artifact_for_test(
state_root: &Path,
agent_id: &str,
messages: &[Message],
) -> Result<PathBuf> {
let mut writer = SubAgentTranscriptArtifactWriter::create(state_root, agent_id)?;
writer.sync_messages(messages, true)?;
Ok(writer.path)
}View on GitHub (pinned to 0c42157ee5)
Solutions
- Inspect the path with ls -l / readlink; if the symlink is intentional and safe, remove it manually with rm on the link itself.
- Restore a regular file (or let the manager recreate it) and retry cleanup.
- Keep the state root free of symlinks and external mounts.
Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::symlink_metadata(&artifact_path)?;
let ok = !meta.file_type().is_symlink() && meta.file_type().is_file();
if !ok { /* do not call remove; handle the symlink/special file manually */ } Type guard
fn is_removable_regular_file(meta: &std::fs::Metadata) -> bool {
!meta.file_type().is_symlink() && meta.file_type().is_file()
} Try / catch
match remove_subagent_transcript_artifact(&state_root, agent_id) {
Err(e) if e.to_string().contains("not a regular file") => { /* inspect with readlink, remove link manually, log */ }
r => r,
} Prevention
- Keep the state root free of symlinks and special files.
- Monitor for child processes creating links inside state dirs.
When it happens
Trigger: The artifact path was replaced by a symlink (accidental or hostile), or the file became a fifo/socket/directory while the manager held the record.
Common situations: State dir manipulated by other tooling or a compromised child; users "organizing" state with symlinks; container mounts overlaying state paths.
Related errors
- sub-agent state path must not traverse symlinks: {}
- sub-agent state path must be a regular file: {}
- config path must not be a symlink: {}
- Agent not found in the active session
- sub-agent transcript history shrank from {} to {} messages
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/b5a34e82248e57cd.
Report an issue: GitHub.