Hmbown/CodeWhale · error

file, not a directory

Error message

file, not a directory

What it means

A test assertion message ("file, not a directory") used in the config setup-transaction tests: it documents the expected failure mode when the config path or a sibling stage target is occupied by a directory — the transaction should fail because a regular file was required, and the test asserts the rollback/diagnostic behavior around that failure.

Solutions

  1. Remove or relocate the directory occupying the expected file path
  2. Adjust the setup so the path under test is a regular file before running the transaction
  3. If the code should tolerate this case, change the product behavior and the test expectation together, not just the test
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/config/src/tests.rs:4323 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/df892cd849940756. Report an issue: GitHub.

Appendix: source

Thrown at crates/config/src/tests.rs:4323

    let body = fs::read_to_string(&config_path).expect("read config");
    assert!(body.contains("# my model"), "prefix comment preserved");
    assert!(body.contains("# end comment"), "suffix comment preserved");
    assert!(body.contains("model = \"deepseek-v4-pro\""));
    assert!(state_path.exists(), "sibling setup state written");
}

#[test]
fn setup_transaction_rolls_back_config_store_body_on_sibling_failure() {
    // #3410 rollback expectation: when a sibling stage fails to apply, the
    // already-written config.toml is restored byte-for-byte, comments and
    // all — no half-applied setup.
    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");
    // A parent that is a regular file makes the second stage unwritable.
    let blocker = dir.path().join("blocker");
    fs::write(&blocker, b"file, not a directory").expect("write blocker");

    let mut store = ConfigStore::load(Some(config_path.clone())).expect("load config store");
    store.config.model = Some("deepseek-v4-pro".to_string());

    let mut transaction = persistence::SetupTransaction::new();
    transaction.stage(
        &config_path,
        store.rendered_body().expect("rendered body").into_bytes(),
    );
    transaction.stage(blocker.join("nested.json"), b"{}".to_vec());
    transaction
        .commit()
        .expect_err("commit must fail on unwritable sibling");

    let body = fs::read_to_string(&config_path).expect("read config");
    assert_eq!(body, original, "config restored byte-for-byte on rollback");
}

View on GitHub (pinned to 433685b202)