tonhowtf/omniget · error · anyhow::Error

escolha ao menos um formato

Error message

escolha ao menos um formato

What it means

substack::run requires at least one output format to be enabled. If all of opts.markdown, opts.html and opts.json are false there is nothing to render, so it fails fast with 'escolha ao menos um formato' (choose at least one format).

Solutions

  1. Enable at least one of opts.markdown, opts.html or opts.json before calling run
  2. Default the UI to a sensible preset (e.g. markdown on)
  3. Validate the combination in the caller and surface the requirement before invoking run

Example fix

// before
let opts = Options { dest: dest.into(), markdown: false, html: false, json: false, .. };
// after
let opts = Options { dest: dest.into(), markdown: true, html: false, json: true, .. };
Defensive patterns

Strategy: validation

Validate before calling

if !(opts.markdown || opts.html || opts.json) {
    anyhow::bail!("at least one output format must be selected");
}

Type guard

fn has_format(opts: &Options) -> bool { opts.markdown || opts.html || opts.json }

Prevention

When it happens

Trigger: Calling run(&opts, progress) with an Options struct where markdown == false && html == false && json == false.

Common situations: UI checkboxes all left unchecked; options restored from saved settings that lost their booleans; caller constructed Options::default() where all format flags are false.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/41ab0fac4689ae62. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/blogs/substack.rs:390

    let v = fetcher
        .get_json("https://substack.com/api/v1/subscriptions")
        .await?;
    let subs = parse_subscriptions(&v);
    if subs.is_empty() {
        return Err(anyhow!(
            "a conta logada não tem nenhuma assinatura ativa (ou a sessão expirou)"
        ));
    }
    Ok(subs)
}

pub async fn run(opts: &Options, progress: ProgressFn) -> Result<ArchiveResult> {
    let dest = opts.dest.trim();
    if dest.is_empty() {
        return Err(anyhow!("escolha a pasta de destino"));
    }
    if !opts.markdown && !opts.html && !opts.json {
        return Err(anyhow!("escolha ao menos um formato"));
    }
    let root = PathBuf::from(dest);
    std::fs::create_dir_all(&root)?;

    let domains: Vec<String> = COOKIE_DOMAINS.iter().map(|d| d.to_string()).collect();
    let fetcher = Fetcher::new(opts.delay_ms, opts.session_netscape.as_deref(), &domains)?;

    // Lista de publicações: o que o usuário digitou tem precedência; vazio
    // significa "as minhas assinaturas".
    let targets: Vec<Subscription> = if opts.publications.is_empty() {
        crate::core::tools::report(
            &progress,
            ID,
            "discover",
            0,
            None,
            Some("assinaturas".into()),
        );

View on GitHub (pinned to 8600b91f42)