flxzt/rnote · error

on-conflict behaviour is still Ask after prompting the user.

Error message

on-conflict behaviour is still Ask after prompting the user.

What it means

In rnote-cli's `file_conflict_prompt_action` (crates/rnote-cli/src/export.rs:485), after resolving the on-conflict policy — either from the remembered `on_conflict_overwrite` value or from an interactive dialoguer prompt — the resolved policy is still `OnConflict::Ask`. Since `Ask` is only a placeholder meaning "query the user", reaching the final match with it means the resolution step failed to produce a concrete action (typically because `on_conflict_overwrite` was explicitly seeded with `Some(Ask)`). The function treats this as an internal invariant violation and aborts the export.

Solutions

  1. Initialize `on_conflict_overwrite` to `None` (or `Some(Overwrite)`/`Some(Skip)`/`Some(Suffix)`) before calling the export functions; never seed it with `OnConflict::Ask`.
  2. Pass an explicit concrete `--on-conflict` value (e.g. overwrite, skip, suffix) so `Ask` never enters the resolution path.
  3. If you must keep `Some(Ask)`, ensure the interactive prompt loop runs first (the loop is only entered when `on_conflict_overwrite` is `None`) — remove the pre-seeded value so the user actually gets prompted.
  4. Library fix: normalize `OnConflict::Ask` to a concrete variant whenever it appears in `on_conflict_overwrite`, or treat `Some(Ask)` as `None` at the top of `file_conflict_prompt_action`.

Example fix

// before
let mut on_conflict_overwrite: Option<OnConflict> = Some(OnConflict::Ask);
export_to_file(..., on_conflict, &mut on_conflict_overwrite, ...).await?;
// after
let mut on_conflict_overwrite: Option<OnConflict> = None; // let the prompt resolve Ask
export_to_file(..., on_conflict, &mut on_conflict_overwrite, ...).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the export API, never seed the memo with Ask:
let mut on_conflict_overwrite: Option<OnConflict> = match on_conflict {
    OnConflict::Ask => None, // let the interactive prompt resolve it
    other => Some(other),
};
if output_file.exists() && on_conflict_overwrite == Some(OnConflict::Ask) {
    anyhow::bail!("--on-conflict ask cannot be pre-selected; use overwrite|skip|suffix");
}

Type guard

fn is_concrete_conflict_policy(p: &OnConflict) -> bool {
    !matches!(p, OnConflict::Ask | OnConflict::AlwaysOverwrite | OnConflict::AlwaysSkip | OnConflict::AlwaysSuffix)
}

Prevention

When it happens

Trigger: Calling `get_output_file_path` or `doc_page_determine_output_file` for a target path that already exists while `on_conflict_overwrite` is `Some(OnConflict::Ask)` (a stale/incorrectly-initialized memoized value), so the prompt loop at line 456 (`while matches!(on_conflict, OnConflict::Ask)`) is skipped entirely and the first match at line 483 sees `Ask`.

Common situations: Programmatic/embedded use of the CLI export API where the `on_conflict_overwrite` out-parameter was initialized to `Some(Ask)` instead of `None`; state carried over from a previous session where the user was never asked; running in a non-interactive environment combined with a hand-built `OnConflict` value that a user would normally never select via `--on-conflict`.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08). Data as JSON: /api/errors/3f15bb1f1132c3b8. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-cli/src/export.rs:485

                    ))
                    .items(options)
                    .default(1)
                    .interact()
                {
                    Ok(0) => cli::open_file_default_app(output_file)?,
                    Ok(c) => on_conflict = options[c],
                    Err(e) => {
                        return Err(anyhow::anyhow!(
                            "Failed to show select prompt, retry or select the behavior with\"--on-conflict\", Err: {e:?}"
                        ));
                    }
                };
            }
        }
    };
    match on_conflict {
        OnConflict::Ask => {
            return Err(anyhow::anyhow!(
                "on-conflict behaviour is still Ask after prompting the user."
            ));
        }
        OnConflict::AlwaysOverwrite => {
            on_conflict = OnConflict::Overwrite;
            *on_conflict_overwrite = Some(on_conflict);
        }
        OnConflict::AlwaysSkip => {
            on_conflict = OnConflict::Skip;
            *on_conflict_overwrite = Some(on_conflict);
        }
        OnConflict::AlwaysSuffix => {
            on_conflict = OnConflict::Suffix;
            *on_conflict_overwrite = Some(on_conflict);
        }
        OnConflict::Overwrite | OnConflict::Skip | OnConflict::Suffix => (),
    }
    match on_conflict {

View on GitHub (pinned to bbc5354502)