tonhowtf/omniget · error

escolha a pasta de destino

Error message

escolha a pasta de destino

What it means

Thrown at the top of the Goodreads export tool's run() when the required destination folder option is blank or whitespace-only. The tool needs a directory where it writes goodreads_library_export.csv and generated output files, so it refuses to run without one.

Solutions

  1. Set opts.dest to an existing or creatable directory path before calling run.
  2. Validate the destination field in your UI/config layer and require a non-empty value.
  3. Trim user input and store the trimmed path in Options.

Example fix

// before
let opts = Options { dest: cfg.dest, .. };
// after
let dest = cfg.dest.trim();
if dest.is_empty() { return Err(anyhow!("escolha a pasta de destino")); }
let opts = Options { dest: dest.to_string(), .. };
Defensive patterns

Strategy: validation

Validate before calling

if opts.dest.trim().is_empty() {
    return Err(anyhow!("dest é obrigatório: informe a pasta de saída"));
}
std::fs::create_dir_all(opts.dest.trim())?;

Type guard

fn has_dest(opts: &Options) -> bool {
    !opts.dest.trim().is_empty()
}

Try / catch

match run(&opts, &p).await {
    Err(e) if e.to_string().contains("pasta de destino") => eprintln!("selecione uma pasta de destino antes de exportar"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling run(&opts, p) where opts.dest is "" or contains only whitespace (opts.dest.trim().is_empty()).

Common situations: UI form left empty before invoking the tool; config file missing the dest key so the default empty string is used; trailing-space-only input that survives validation.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/lists/goodreads.rs:511

    let base: String = crate::core::tools::music::norm::strip_accents(s)
        .to_lowercase()
        .chars()
        .map(|c| if c.is_alphanumeric() { c } else { '-' })
        .collect();
    let parts: Vec<&str> = base.split('-').filter(|p| !p.is_empty()).collect();
    let s = parts.join("-");
    if s.is_empty() {
        "prateleira".to_string()
    } else {
        s
    }
}

// ── Execução ────────────────────────────────────────────────────────────

pub async fn run(opts: &Options, p: ProgressFn) -> Result<ExportResult> {
    if opts.dest.trim().is_empty() {
        return Err(anyhow!("escolha a pasta de destino"));
    }
    let dest = PathBuf::from(opts.dest.trim());
    std::fs::create_dir_all(&dest)?;
    let f = Fetcher::new(opts.delay_ms, opts.session_netscape.as_deref(), DOMAIN)?;

    let (csv, source, waited) = match opts.csv_path.as_deref().map(str::trim) {
        Some(path) if !path.is_empty() => (
            std::fs::read_to_string(path).with_context(|| format!("não consegui ler {}", path))?,
            path.to_string(),
            0,
        ),
        _ => {
            if !f.has_session() {
                return Err(anyhow!(
                    "sem sessão do Goodreads: capture os cookies de goodreads.com na extensão, ou aponte o goodreads_library_export.csv que você já baixou"
                ));
            }
            let (csv, secs) = trigger_and_wait(&f, opts, &p).await?;

View on GitHub (pinned to 8600b91f42)