screenpipe/screenpipe · error
skill files cannot contain NUL bytes: {}
Error message
skill files cannot contain NUL bytes: {} What it means
Every file in a skill bundle must be valid UTF-8 text (this is enforced by `String::from_utf8` right before this check) and must not contain NUL bytes ('\0'). Binary content or text with embedded NULs aborts the bundle with this error. This guarantees bundle files are safe, printable text.
Source
Thrown at crates/screenpipe-engine/src/cli/team_skills.rs:325
if !metadata.is_file() {
anyhow::bail!("skill bundle contains a non-file: {}", path.display());
}
if files.len() >= MAX_FILES {
anyhow::bail!("skill bundle has too many files (max {MAX_FILES})");
}
let bytes = std::fs::read(&path)?;
if bytes.len() > MAX_FILE_BYTES {
anyhow::bail!("skill file is too large: {}", path.display());
}
*total_bytes += bytes.len();
if *total_bytes > MAX_TOTAL_BYTES {
anyhow::bail!("skill bundle is too large (max {MAX_TOTAL_BYTES} bytes)");
}
let content = String::from_utf8(bytes)
.with_context(|| format!("skill files must be UTF-8 text: {}", path.display()))?
.replace("\r\n", "\n");
if content.contains('\0') {
anyhow::bail!("skill files cannot contain NUL bytes: {}", path.display());
}
let relative = path
.strip_prefix(root)?
.to_string_lossy()
.replace('\\', "/");
if relative.split('/').count() > MAX_DEPTH {
anyhow::bail!("skill file path is nested too deeply: {relative}");
}
files.push((relative, content));
}
Ok(())
}
fn parse_frontmatter(raw: &str) -> anyhow::Result<(String, String)> {
let normalized = raw.replace("\r\n", "\n");
let rest = normalized
.strip_prefix("---\n")
.ok_or_else(|| anyhow::anyhow!("SKILL.md needs YAML frontmatter"))?;View on GitHub (pinned to 4ebf712990)
Solutions
- Remove binary files from the skill directory — only UTF-8 text files are allowed
- Re-save any UTF-16 encoded file as UTF-8 (e.g. in the editor's save-as dialog, or `iconv -f UTF-16 -t UTF-8`)
- Check for corrupted files that contain NUL bytes (grep -P '\x00' -rl .) and regenerate them
- Move binary assets outside the bundle and reference them by path or URL in the skill instructions
Example fix
// before: notes.md saved as UTF-16 (contains NUL bytes) // after iconv -f UTF-16 -t UTF-8 notes.md > notes-utf8.md && mv notes-utf8.md notes.md
Defensive patterns
Strategy: validation
Validate before calling
fn assert_utf8_no_nul(root: &std::path::Path) -> anyhow::Result<()> {
for entry in walkdir::WalkDir::new(root).into_iter().filter_map(Result::ok) {
if entry.file_type().is_file() {
let bytes = std::fs::read(entry.path())?;
String::from_utf8(bytes).map_err(|_| {
anyhow::anyhow!("non-UTF-8 file: {}", entry.path().display())
})?;
let text = std::fs::read_to_string(entry.path())?;
if text.contains('\0') {
anyhow::bail!("NUL byte in: {}", entry.path().display());
}
}
}
Ok(())
} Type guard
fn is_clean_utf8(bytes: &[u8]) -> bool {
std::str::from_utf8(bytes).map(|s| !s.contains('\0')).unwrap_or(false)
} Try / catch
match prepare_bundle(&skill_dir) {
Err(e) if e.to_string().contains("NUL") || e.to_string().contains("UTF-8") => {
eprintln!("remove binaries and re-save files as UTF-8: {e}");
}
other => other?,
} Prevention
- Keep only text files in skill bundles; store binaries elsewhere
- Save all editors' files as UTF-8 (never UTF-16), especially on Windows
- Scan before bundling: grep -rlP '\x00' .
- Watch for git-lfs placeholders and downloaded binaries sneaking into the folder
When it happens
Trigger: Bundling a skill directory that includes a binary file (image, compiled object, .png, .woff) or a text file corrupted with embedded NUL bytes (e.g. UTF-16 files whose byte pairs look like NUL-padded ASCII).
Common situations: Accidentally placing images or downloaded binaries in the skill folder; saving SKILL.md or scripts in UTF-16 encoding from some Windows editors; git-lfs placeholder files; log files with binary garbage.
Related errors
- action must be list, read, create, or patch
- create requires explicit user confirmation
- query is required
- connectionId is required
- unsupported Live View action: ${action || "<missing>"}
AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01).
Data as JSON: /api/errors/3f1664d2f84b34e9.
Report an issue: GitHub.