tonhowtf/omniget · error

escolha a pasta de destino

Error message

escolha a pasta de destino

What it means

Thrown at the start of the Letterboxd export tool's run() when opts.dest is blank or whitespace-only. Like the Goodreads tool, a destination directory is required because the tool writes the extracted export CSVs and generated output there.

Solutions

  1. Set opts.dest to a valid directory path before calling run.
  2. Add UI/config validation requiring a non-empty destination.
  3. Trim and normalize the destination input before constructing Options.

Example fix

// before
let opts = Options { dest: String::new(), .. };
letterboxd::run(&opts, p).await?;
// after
let opts = Options { dest: "/home/user/exports/letterboxd".into(), .. };
letterboxd::run(&opts, p).await?;
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 letterboxd::run(&opts, &p).await {
    Err(e) if e.to_string().contains("pasta de destino") => eprintln!("escolha a pasta de destino no formulário"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling run(&opts, p) with opts.dest set to "" or only whitespace.

Common situations: Destination field not filled in the UI; config file missing dest; user pasted a path with only spaces; defaults not initialized.

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/fc1e522a2dd727fe. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/lists/letterboxd.rs:356

/// Junta as partes numa lista só, sem perder de que parte cada linha veio.
fn flatten(parts: Vec<(String, Vec<Entry>)>) -> (Vec<Entry>, Vec<PartCount>) {
    let mut counts = Vec::new();
    let mut all = Vec::new();
    for (label, entries) in parts {
        counts.push(PartCount {
            part: label,
            entries: entries.len(),
        });
        all.extend(entries);
    }
    all.sort_by(|a, b| b.date.cmp(&a.date).then(a.title.cmp(&b.title)));
    (all, counts)
}

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

    // 1. O ZIP: local ou baixado com a sessão.
    let (bytes, source) = match opts.zip_path.as_deref().map(str::trim) {
        Some(path) if !path.is_empty() => {
            report(&p, TOOL_ID, "progress", 0, Some(3), Some(path.to_string()));
            (
                std::fs::read(path).with_context(|| format!("não consegui ler {}", path))?,
                path.to_string(),
            )
        }
        _ => {
            if !f.has_session() {
                return Err(anyhow!(
                    "sem sessão do Letterboxd: capture os cookies de letterboxd.com na extensão, ou aponte um ZIP já baixado de letterboxd.com/settings/data/"
                ));

View on GitHub (pinned to 8600b91f42)