tonhowtf/omniget · error

não achei nenhum StreamingHistory_*.json /…

Error message

não achei nenhum StreamingHistory_*.json / Streaming_History_Audio_*.json

What it means

Thrown by music history's `run` when `collect_sources` over the given inputs finds zero files matching `StreamingHistory_*.json` or `Streaming_History_Audio_*.json`. Spotify's history export must contain at least one of these files for the analysis to proceed.

Solutions

  1. Point `inputs` at the extracted Spotify data export directory containing the history JSONs
  2. Check filenames match the patterns exactly (rename if needed)
  3. Extract the export zip first — the tool won't read archives
  4. Confirm the export actually includes streaming history (some exports omit it)

Example fix

// before
HistoryOptions { inputs: vec!["~/Downloads/mydata.zip".into()] }
// after
HistoryOptions { inputs: vec!["~/Downloads/mydata/".into()] } // extracted dir with Streaming_History_Audio_*.json
Defensive patterns

Strategy: validation

Validate before calling

let has_history = std::fs::read_dir(input_dir)?
    .filter_map(|e| e.ok())
    .any(|e| {
        let n = e.file_name().to_string_lossy().into_owned();
        n.starts_with("StreamingHistory_") || n.starts_with("Streaming_History_Audio_")
    }) && std::path::Path::new(input_dir).is_dir();
if !has_history {
    return Err("folder contains no Spotify streaming history JSON files".into());
}

Type guard

fn contains_history_files(dir: &str) -> bool {
    std::fs::read_dir(dir).map(|rd| rd.filter_map(|e| e.ok()).any(|e| {
        let n = e.file_name().to_string_lossy();
        n.starts_with("StreamingHistory_") || n.starts_with("Streaming_History_Audio_")
    })).unwrap_or(false)
}

Try / catch

match history::run(&opts, &progress) {
    Ok(result) => show(result),
    Err(e) if e.to_string().contains("StreamingHistory") => show_export_instructions(),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `run(&HistoryOptions { inputs: [paths..] }, ..)` where none of the input paths/directories contain files matching either glob pattern.

Common situations: User unzipped the Spotify export but points the tool at the wrong folder; renamed the JSON files; Spotify changed export filenames between years (StreamingHistory vs Streaming_History_Audio); passing the zip itself instead of extracted files.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/music/history.rs:750

                    r.exports.push(p.to_string_lossy().to_string());
                }
            }
            "md" => {
                let p = out_dir.join("historico-spotify.md");
                std::fs::write(&p, report_markdown(r))?;
                r.exports.push(p.to_string_lossy().to_string());
            }
            _ => {}
        }
    }
    Ok(())
}

pub fn run(opts: &HistoryOptions, p: &ProgressFn) -> Result<HistoryResult> {
    report(p, TOOL_ID, "started", 0, None, None);
    let sources = collect_sources(&opts.inputs)?;
    if sources.is_empty() {
        anyhow::bail!("não achei nenhum StreamingHistory_*.json / Streaming_History_Audio_*.json");
    }
    let total = sources.len() as u64;
    let mut plays = Vec::new();
    let mut files = Vec::new();
    for (i, (name, text)) in sources.iter().enumerate() {
        report(
            p,
            TOOL_ID,
            "progress",
            i as u64 + 1,
            Some(total),
            Some(name.clone()),
        );
        let mut got = parse_history(text, opts.min_ms);
        if !got.is_empty() {
            files.push(name.clone());
            plays.append(&mut got);
        }

View on GitHub (pinned to 8600b91f42)