Hmbown/CodeWhale · warning · io::Error
file appears to be binary
Error message
file appears to be binary
What it means
read_text_prefix reads the beginning of a file for @-mention content and rejects files whose buffered bytes contain a NUL byte (a strong binary signal). This InvalidData error ('file appears to be binary') is thrown before attempting UTF-8 conversion so binary media is never injected as text.
Solutions
- Mention a text file instead, or convert the binary asset to text/summary first
- Check the file type before mentioning (e.g. `file` command) and skip binary outputs
- Extend is_media_path coverage if a known binary extension slips through
- Handle InvalidData from read_file_content and show a 'binary file skipped' note
Example fix
// before
let (text, _) = read_file_content(&path)?;
// after
let (text, _) = match read_file_content(&path) {
Ok(t) => t,
Err(e) if e.kind() == io::ErrorKind::InvalidData => return Ok("[binary file omitted]".into()),
Err(e) => return Err(e.into()),
}; Defensive patterns
Strategy: validation
Validate before calling
let head = std::fs::read(&path)?;
if head.iter().take(8192).any(|&b| b == 0) {
// binary; skip before calling read_file_content
} Type guard
fn looks_like_text(bytes: &[u8]) -> bool {
!bytes.iter().take(8192).any(|&b| b == 0)
} Try / catch
match read_file_content(&path) {
Err(e) if e.kind() == io::ErrorKind::InvalidData => "[binary file omitted]".to_string(),
other => other?.0,
} Prevention
- Filter known binary extensions before mention
- Sniff the first KB for NUL bytes before reading as text
- Prefer the media-file summary path for binaries
- Keep is_media_path's extension list current
When it happens
Trigger: Calling read_file_content / read_text_prefix on a file whose first bytes include a 0x00 byte — images, compiled objects, archives, PDFs, or any binary blob that is not filtered by is_media_path.
Common situations: Mentioning a binary file whose extension is not in the media-extension list (e.g. extensionless executables, .dat, .bin); a corrupted text file with embedded NULs.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- file is not UTF-8
- stream did not contain valid UTF-8
- artifact name is not portable UTF-8
- Cannot open session : its queued input is already open in…
- Checkpoint schema v is newer than supported v
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/ca440812b259277b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/file_mention.rs:1413
.take(MAX_MENTION_FILE_BYTES + 1)
.read_to_end(&mut buffer)?;
let truncated = buffer.len() as u64 > MAX_MENTION_FILE_BYTES;
if truncated {
buffer.truncate(MAX_MENTION_FILE_BYTES as usize);
// Round down to the nearest valid UTF-8 character boundary so a
// multi-byte sequence (CJK, emoji, etc.) is never split at the cut point.
// Only adjust when error_len() is None — that means truncation landed
// mid-sequence (incomplete tail). A Some(_) error_len means the file
// genuinely contains invalid UTF-8 bytes; leave the buffer intact so
// the from_utf8 call below returns the correct "file is not UTF-8" error.
if let Err(e) = std::str::from_utf8(&buffer)
&& e.error_len().is_none()
{
buffer.truncate(e.valid_up_to());
}
}
if buffer.contains(&0) {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"file appears to be binary",
));
}
let text = std::str::from_utf8(&buffer)
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "file is not UTF-8"))?
.to_string();
Ok((text, truncated))
}
fn is_media_path(path: &Path) -> bool {
let Some(ext) = path.extension().and_then(|ext| ext.to_str()) else {
return false;
};
matches!(
ext.to_ascii_lowercase().as_str(),
"png"
| "jpg"View on GitHub (pinned to 73e0f67d83)