AprilNEA/OpenLogi · error
in-progress contribution contains a non-UTF-8 entry
Error message
in-progress contribution contains a non-UTF-8 entry
What it means
During the same pre-publish layout audit of the contribution directory, any directory entry whose filename is not valid UTF-8 cannot be matched against the expected entry names (state, profile, manifest, cases). Since the tool cannot classify it, it bails with this message rather than publishing over or silently deleting unknown content. Filenames here are expected to be UTF-8 (they become part of committed fixture data).
Solutions
- Find the offending entry (`find DIR -name '*\?*'` or `ls -b DIR`) and delete or rename it to valid UTF-8, then rerun.
- Recreate the contribution directory with clean UTF-8 content: move expected files out, remove the directory, and rerun the contribute workflow.
- Avoid copying contribution directories through non-UTF-8-preserving tools or legacy network shares.
- If this recurs without explanation, check the filesystem for corruption (`fsck` on Linux, Disk Utility first aid on macOS).
Example fix
# before ls -b fx/ -> profile.json state.json fx\xff\xfe/ # error: non-UTF-8 entry # after rm -rf 'fx/'fx$'\xff\xfe' # or rename it to a UTF-8 name openlogi fixture contribute --output fx ...
Defensive patterns
Strategy: validation
Validate before calling
fn has_non_utf8_names(dir: &Path) -> anyhow::Result<bool> {
Ok(fs::read_dir(dir)?
.filter_map(Result::ok)
.any(|e| e.file_name().to_str().is_none()))
}
// if true, find and rename/remove the offending entry before publishing Prevention
- Copy contribution directories only through UTF-8-preserving tools and filesystems (avoid legacy network shares).
- Use `ls -b` to spot non-ASCII byte sequences in filenames before resuming.
- Extract archives with tools that preserve or normalize UTF-8 names.
- Keep the contribution directory local (e.g. ext4/APFS), not on mounted shares with legacy encoding.
When it happens
Trigger: Running the publish/finish phase of `openlogi fixture contribute` when the contribution directory contains an entry with non-UTF-8 bytes in its name — typically created by a tool on a platform/filesystem with different encoding conventions, or by a filesystem-corruption event.
Common situations: Files created with legacy encodings (e.g. Latin-1 names via Samba/NFS mounts or old archive extraction) inside DIR; mangled names after a failed copy; filesystem corruption; copying the contribution directory through a tool that re-encoded names.
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
- already exists but is not an in-progress OpenLogi…
- in-progress contribution contains unexpected entry
- resumable fixture cases contain a non-UTF-8 entry
- fixture directory has no UTF-8 synthetic ID
- saved contribution profile does not match its resumable…
AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13).
Data as JSON: /api/errors/8d04e20e45ba3b5f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/openlogi-cli/src/cmd/fixture/contribute.rs:295
fn validate_resumable_layout(directory: &Path, cassettes: &[HidCassette]) -> Result<()> {
for entry in
fs::read_dir(directory).context("could not inspect resumable contribution directory")?
{
let entry = entry.context("could not inspect resumable contribution entry")?;
let name = entry.file_name();
match name.to_str() {
Some(STATE_FILE | PROFILE_FILE) => {}
Some(MANIFEST_FILE) => require_regular_file(&entry.path(), "fixture manifest")?,
Some(CASES_DIRECTORY) if !cassettes.is_empty() => {
require_directory(&entry.path(), "fixture cases directory")?;
validate_resumable_cases(&entry.path(), cassettes)?;
}
Some(other) => bail!(
"in-progress contribution contains unexpected entry {other:?}; refusing to \
publish over it"
),
None => bail!("in-progress contribution contains a non-UTF-8 entry"),
}
}
Ok(())
}
fn validate_resumable_cases(directory: &Path, cassettes: &[HidCassette]) -> Result<()> {
let expected = cassettes
.iter()
.map(|cassette| format!("{}.json", cassette.name))
.collect::<Vec<_>>();
for entry in fs::read_dir(directory).context("could not inspect resumable fixture cases")? {
let entry = entry.context("could not inspect resumable fixture case")?;
let name = entry.file_name();
let Some(name) = name.to_str() else {
bail!("resumable fixture cases contain a non-UTF-8 entry");
};
if !expected.iter().any(|expected| expected == name) {
bail!("resumable fixture cases contain unexpected file {name:?}");View on GitHub (pinned to e846e6f4b4)