AprilNEA/OpenLogi · error
resumable fixture cases contain unexpected file
Error message
resumable fixture cases contain unexpected file {name:?} What it means
While validating a resumed contribution, every file found in the `cases/` directory must exactly match one of the cassette filenames (`<cassette-name>.json`) recorded in the resumable state. Any extra or differently-named entry causes this bail, preventing the CLI from publishing a fixture whose cassette set doesn't match the recorded state.
Solutions
- Inspect `<output>/cases/` and remove any file that isn't a cassette expected by the current contribution (backups, `.DS_Store`, stale JSON)
- If the extra file belongs to the fixture, delete the resumable state file and restart the contribution so the state is regenerated consistently
- Never manually add/rename cassette JSON files inside an in-progress contribution directory
- Use a fresh output directory per contribution id
Example fix
// before: resumable cases dir polluted by an editor backup $ ls output/cases/ my-cassette.json my-cassette.json~ // after: remove the unexpected file and rerun $ rm output/cases/my-cassette.json~ $ openlogi fixture contribute ... # validation passes
Defensive patterns
Strategy: validation
Validate before calling
use std::fs;
fn cases_match_expected(cases_dir: &std::path::Path, expected: &[String]) -> std::io::Result<bool> {
let mut actual: Vec<String> = fs::read_dir(cases_dir)?
.filter_map(|e| e.ok())
.filter_map(|e| e.file_name().to_str().map(str::to_string))
.collect();
actual.sort();
let mut sorted = expected.to_vec();
sorted.sort();
Ok(actual == sorted)
} Type guard
fn is_expected_cassette(name: &str, expected: &[String]) -> bool {
expected.iter().any(|e| e == name)
} Prevention
- Never reuse an output directory across contribution ids; one directory per fixture
- Disable editor backup files in the fixture output directory (no `*~`, no `.DS_Store` — add it to editor ignore rules)
- Delete the resumable state file rather than hand-editing cassettes when something goes wrong
- Run `openlogi fixture verify` before resuming a contribution
When it happens
Trigger: Resuming `openlogi fixture contribute` when `<output>/cases/` contains a file not listed in the resumable state — e.g. leftover cassette JSON from a previous attempt with a different fixture id, editor backup files (`foo.json~`, `.DS_Store`), or a manually renamed/added cassette file.
Common situations: Reusing an output directory across contribution attempts with different `--id`; editors or OS tools leaving backup/metadata files in the cases directory; hand-renaming a cassette JSON to fix a typo; interrupted earlier run leaving stale cassettes.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- resumable fixture cases contain a non-UTF-8 entry
- fixture directory has no UTF-8 synthetic ID
- already exists but is not an in-progress OpenLogi…
- in-progress contribution contains unexpected entry
- in-progress contribution contains a non-UTF-8 entry
AI-assisted analysis of AprilNEA/OpenLogi@e846e6f4b4 (2026-09-13).
Data as JSON: /api/errors/54123efcd0f117e3.
Report an issue: GitHub.
Appendix: source
Thrown at crates/openlogi-cli/src/cmd/fixture/contribute.rs:313
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:?}");
}
require_regular_file(&entry.path(), "fixture cassette")?;
}
Ok(())
}
fn identity_plan(
profile: &DeviceProfile,
selected_route: &DeviceRoute,
) -> Result<HidCassetteIdentityPlan> {
let mut plan = HidCassetteIdentityPlan::default();
let model = match selected_route {
DeviceRoute::Bolt { receiver_uid, slot } => {
plan.insert(
SanitizedIdentityKind::ReceiverUniqueId,
receiver_uid.as_bytes().to_vec(),
)?;
selected_model(profile, selected_route, *slot)?View on GitHub (pinned to e846e6f4b4)