{"record":{"id":"ca440812b259277b","repo":"Hmbown/CodeWhale","slug":"file-appears-to-be-binary","errorCode":null,"errorMessage":"file appears to be binary","messagePattern":"file appears to be binary","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"warning","filePath":"crates/tui/src/tui/file_mention.rs","lineNumber":1413,"sourceCode":"        .take(MAX_MENTION_FILE_BYTES + 1)\n        .read_to_end(&mut buffer)?;\n    let truncated = buffer.len() as u64 > MAX_MENTION_FILE_BYTES;\n    if truncated {\n        buffer.truncate(MAX_MENTION_FILE_BYTES as usize);\n        // Round down to the nearest valid UTF-8 character boundary so a\n        // multi-byte sequence (CJK, emoji, etc.) is never split at the cut point.\n        // Only adjust when error_len() is None — that means truncation landed\n        // mid-sequence (incomplete tail).  A Some(_) error_len means the file\n        // genuinely contains invalid UTF-8 bytes; leave the buffer intact so\n        // the from_utf8 call below returns the correct \"file is not UTF-8\" error.\n        if let Err(e) = std::str::from_utf8(&buffer)\n            && e.error_len().is_none()\n        {\n            buffer.truncate(e.valid_up_to());\n        }\n    }\n    if buffer.contains(&0) {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidData,\n            \"file appears to be binary\",\n        ));\n    }\n    let text = std::str::from_utf8(&buffer)\n        .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, \"file is not UTF-8\"))?\n        .to_string();\n    Ok((text, truncated))\n}\n\nfn is_media_path(path: &Path) -> bool {\n    let Some(ext) = path.extension().and_then(|ext| ext.to_str()) else {\n        return false;\n    };\n    matches!(\n        ext.to_ascii_lowercase().as_str(),\n        \"png\"\n            | \"jpg\"","sourceCodeStart":1395,"sourceCodeEnd":1431,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/file_mention.rs#L1395-L1431","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet (text, _) = read_file_content(&path)?;\n// after\nlet (text, _) = match read_file_content(&path) {\n    Ok(t) => t,\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => return Ok(\"[binary file omitted]\".into()),\n    Err(e) => return Err(e.into()),\n};","handlingStrategy":"validation","validationCode":"let head = std::fs::read(&path)?;\nif head.iter().take(8192).any(|&b| b == 0) {\n    // binary; skip before calling read_file_content\n}","typeGuard":"fn looks_like_text(bytes: &[u8]) -> bool {\n    !bytes.iter().take(8192).any(|&b| b == 0)\n}","tryCatchPattern":"match read_file_content(&path) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => \"[binary file omitted]\".to_string(),\n    other => other?.0,\n}","preventionTips":["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"],"tags":["io","binary-file","encoding","file-read"],"backgroundTag":"file-read-failed","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"}