Hmbown/CodeWhale · error

No loaded config file can receive this confirmation

Error message

No loaded config file can receive this confirmation

What it means

record_confirmation persists the user's explicit 'disable model-bound redaction' confirmation into the config file that was loaded at startup. If no config file was loaded (e.g. all defaults, or config came from env/flags), there is no file to write the receipt into and the function refuses.

Solutions

  1. Launch Codewhale with a real config file (default path or --config) so confirmations have somewhere to persist
  2. Create a minimal config file at the default location before confirming
  3. Programmatically set loaded_config_path (or write the confirmation via codewhale_config::redaction::record_model_bound_disabled_confirmation directly to a chosen path)

Example fix

// before
let receipt = redaction_gate::record_confirmation(&config)?;
// after
if config.loaded_config_path.is_none() {
    anyhow::bail!("Start with a config file to record this confirmation.");
}
let receipt = redaction_gate::record_confirmation(&config)?;
Defensive patterns

Strategy: validation

Validate before calling

fn can_record_confirmation(config: &Config) -> bool {
    config.loaded_config_path.is_some()
}

Try / catch

match redaction_gate::record_confirmation(&config) {
    Err(e) if e.to_string().contains("No loaded config file") => {
        eprintln!("Launch with a config file to persist this confirmation.");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling record_confirmation with a Config whose loaded_config_path is None — launched without a config file, with --no-config, or in a test/embedded context where Config was constructed programmatically.

Common situations: User runs Codewhale without any config file and then confirms the redaction prompt; config loaded purely from environment; headless/embedded usage.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/6e0d7e3934d17c88. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tui/redaction_gate.rs:191

/// Supporting hint in the muted lane.
fn wrap_body_muted(lines: &mut Vec<Line<'static>>, app: &App, id: MessageId, width: usize) {
    let text = app.tr(id);
    for segment in wrap_words(&text, width) {
        lines.push(Line::from(Span::styled(
            segment,
            Style::default().fg(palette::TEXT_MUTED),
        )));
    }
}

/// Persist the confirmation and return the written receipt path. Called after
/// the user picks the explicit "confirm" action.
pub fn record_confirmation(config: &crate::config::Config) -> anyhow::Result<std::path::PathBuf> {
    let path = config
        .loaded_config_path
        .as_deref()
        .ok_or_else(|| anyhow::anyhow!("No loaded config file can receive this confirmation"))?;
    codewhale_config::redaction::record_model_bound_disabled_confirmation(path)
        .map_err(anyhow::Error::from)
}

// The "keep masking" answer persists nothing and rewrites no file: the
// current launch stays on the safe default, and because the config field
// still requests `"disabled"`, the gate asks again on the next launch until
// the user confirms or edits the field back to `"enabled"`. The event loop
// implements this inline (it only clears the gate flag); this module-level
// contract comment is where the semantics live.

#[cfg(test)]
mod tests {
    use super::*;
    use crate::config::Config;
    use crate::tui::app::TuiOptions;
    use crate::tui::views::action_footer_lines;
    use std::path::PathBuf;

View on GitHub (pinned to 73e0f67d83)