Hmbown/CodeWhale · error
artifact name is not portable UTF-8
Error message
artifact name is not portable UTF-8
What it means
Artifact file names must be portable UTF-8 and must not contain backslash or colon characters. When a directory entry's name is not valid UTF-8 or contains those characters, the walk aborts with InvalidData so archives stay portable across filesystems and platforms.
Solutions
- Rename the offending artifact file to a portable UTF-8 name without '\\' or ':' and re-export.
- Identify offenders with: find <artifacts_dir> -name '*[\\:]*' and with ls | grep -P '[^\x00-\x7F]'.
- If files came from another platform, normalize names during copy-in rather than at export time.
- Fix the tool that created non-portable names so future sessions export cleanly.
Example fix
// before artifacts/logs/'C:\temp\build.log' // after $ mv 'artifacts/logs/C:\temp\build.log' 'artifacts/logs/C-temp-build.log'
Defensive patterns
Strategy: validation
Validate before calling
fn portable_name(name: &std::ffi::OsStr) -> bool {
name.to_str()
.map(|s| !s.contains('\\') && !s.contains(':'))
.unwrap_or(false)
} Prevention
- Sanitize file names to ASCII/UTF-8 at write time, not at export time.
- Strip drive letters and separators when ingesting files from Windows.
- Enforce a name allowlist (alnum, '-', '_', '.') for artifact writers.
When it happens
Trigger: A file or directory under artifacts/ has a non-UTF-8 (raw byte) name, or its name contains '\\' or ':' — often from files created on another OS or by tools writing raw bytes.
Common situations: Files copied from Windows with names like 'C:\temp\log.txt' baked in; files created on Linux with invalid UTF-8 byte sequences; NFC/NFD or encoding issues from network transfers.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- current Codewhale executable path is not valid UTF-8
- child stdout was not valid UTF-8
- Configuration and skill entrypoints must be UTF-8.
- {err}
- {err}
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/10b3b706c29c32b8.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/session_export.rs:362
for entry in fs::read_dir(dir)? {
let entry = entry?;
*entries += 1;
if *entries > MAX_ARTIFACT_ENTRIES {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"artifact tree exceeds export entry limit",
));
}
let file_type = entry.file_type()?;
if file_type.is_symlink() {
continue;
}
let child = entry.file_name();
let child = child
.to_str()
.filter(|name| !name.contains(['\\', ':']))
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"artifact name is not portable UTF-8",
)
})?;
let member = format!("{prefix}/{child}");
let path = entry.path();
let relative = path.strip_prefix(sessions_dir).map_err(io::Error::other)?;
if file_type.is_dir() {
// Reject substituted parent directories before descending. The file
// read repeats confinement checks, so directory races cannot leak bytes.
WorkspaceFile::open(sessions_dir, &relative.join(".export-root-check"), false)?;
collect_artifact_files_recursive(
sessions_dir,
&path,
&member,
depth + 1,
entries,
files,View on GitHub (pinned to 73e0f67d83)