Hmbown/CodeWhale · warning
seed backup
Error message
seed backup
What it means
A test assertion helper: fs::write(&path, ...).expect("seed backup") panics if writing the seed backup file fails in the scrub_plaintext_api_keys_from_config_backup test at crates/config/src/tests.rs:4203. It is not a library error — it indicates the test fixture could not create its backup file.
Solutions
- Ensure each test creates its own tempfile::tempdir() instead of sharing a path across tests.
- Check the io::Error in the panic message: NotFound -> missing dir, PermissionDenied -> fs perms, IsADirectory -> wrong path.
- Run the single test in isolation (cargo test -p codewhale-config <name>) to rule out parallel-test interference.
Defensive patterns
Strategy: validation
Validate before calling
assert!(backup_path.parent().is_some()); std::fs::create_dir_all(backup_path.parent().unwrap())?;
Try / catch
if let Err(e) = fs::write(&backup_path, contents) {
panic!("seed backup failed ({e:?}): is the tempdir still alive?");
} Prevention
- Give each test its own tempfile::tempdir()
- Keep the TempDir alive until all fixture writes finish
- Read the io::Error kind in the panic before guessing
When it happens
Trigger: The temp directory was deleted before the write, the path is a directory, the disk is full, or permission denied on the fixture path.
Common situations: Flaky CI with parallel tests clobbering a shared path; tests refactored to share one tempdir where one test removed it.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/35ae2754636a90ec.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/tests.rs:4203
.lines()
.any(|line| line.trim_start().starts_with("api_key ="))
);
assert!(backup.contains("api_key_env = \"OPENROUTER_API_KEY\""));
assert!(backup.contains("auth_mode = \"api_key\""));
assert!(backup.contains("default_text_model = \"deepseek-v4-pro\""));
}
#[test]
fn config_backup_scrub_repairs_an_existing_plaintext_backup() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join(CONFIG_FILE_NAME);
fs::write(&path, "model = \"new-model\"\n").expect("seed config");
let backup_path = config_backup_path(&path);
fs::write(
&backup_path,
"api_key = \"old-test-credential\"\nmodel = \"old-model\"\n",
)
.expect("seed backup");
scrub_plaintext_api_keys_from_config_backup(&path).expect("scrub backup");
let backup = fs::read_to_string(backup_path).expect("read backup");
assert!(!backup.contains("old-test-credential"), "{backup}");
assert!(!backup.contains("api_key"), "{backup}");
assert!(backup.contains("model = \"old-model\""));
}
#[test]
fn config_store_save_preserves_comments() {
let dir = tempfile::tempdir().expect("tempdir");
let config_path = dir.path().join(CONFIG_FILE_NAME);
let original = "# my model\nmodel = \"deepseek-v4-flash\"\n# end comment\n";
fs::write(&config_path, original).expect("write config");
let mut store = ConfigStore::load(Some(config_path.clone())).expect("load config store");
store.config.model = Some("deepseek-v4-pro".to_string());View on GitHub (pinned to 433685b202)