{"record":{"id":"a49e610d190494aa","repo":"tonhowtf/omniget","slug":"escolha-a-pasta-de-destino-favorites","errorCode":null,"errorMessage":"escolha a pasta de destino","messagePattern":"escolha a pasta de destino","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/tiktok/favorites.rs","lineNumber":436,"sourceCode":"        if vazio || !has_more || next.is_empty() || next == cursor || out.len() as u32 >= teto {\n            break;\n        }\n        cursor = next;\n    }\n    if out.is_empty() {\n        return Err(anyhow!(\n            \"a lista voltou vazia — o TikTok não entregou os favoritos para esta sessão\"\n        ));\n    }\n    Ok(out)\n}\n\npub async fn run(opts: &Options, progress: ProgressFn) -> Result<FavoritesResult> {\n    if opts.user.trim().is_empty() {\n        return Err(anyhow!(\"informe o perfil (@usuario) ou a URL da coleção\"));\n    }\n    if opts.dest.trim().is_empty() {\n        return Err(anyhow!(\"escolha a pasta de destino\"));\n    }\n    let dest = PathBuf::from(&opts.dest);\n    std::fs::create_dir_all(&dest)?;\n\n    let session = TempCookies::new(opts.session_netscape.as_deref());\n    let used_session = session.is_some();\n    let cookies: Option<PathBuf> = opts\n        .cookies\n        .as_deref()\n        .filter(|c| !c.trim().is_empty())\n        .map(PathBuf::from)\n        .or_else(|| session.path().map(|p| p.to_path_buf()));\n\n    let handle = handle_of(&opts.user);\n    let pacer = Pacer::new(opts.delay_ms);\n    report(&progress, ID, \"started\", 0, None, None);\n\n    let mut entries = match opts.source.as_str() {","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/tiktok/favorites.rs#L418-L454","documentation":"After validating the profile, `run` checks that `opts.dest` names a destination folder; if it is empty or whitespace the tool refuses to proceed with this message. The destination is required because downloaded favorite videos are written to that directory (created immediately afterwards with create_dir_all).","triggerScenarios":"Calling `run(opts, progress)` with `opts.dest` equal to \"\" or whitespace; forgetting to bind the folder-picker result to Options; deserializing Options from a request where the dest key was omitted and defaulted to an empty string.","commonSituations":"A Tauri frontend sends the command without the user having chosen an output folder; config file has an empty `dest` key; a refactor renamed the field and the call site stopped populating it.","solutions":["Set opts.dest to a valid directory path before calling run.","In the UI, require a folder selection before enabling the action.","If dest is omitted, prompt the user or fall back to a sensible default directory upstream."],"exampleFix":"// before\nlet opts = Options { user: \"@someuser\".into(), dest: \"\".into(), ..Default::default() };\n// after\nlet opts = Options { user: \"@someuser\".into(), dest: \"/tmp/favorites\".into(), ..Default::default() };","handlingStrategy":"validation","validationCode":"if opts.dest.trim().is_empty() {\n    return Err(anyhow!(\"escolha a pasta de destino antes de iniciar\"));\n}","typeGuard":"fn has_dest(opts: &Options) -> bool { !opts.dest.trim().is_empty() }","tryCatchPattern":null,"preventionTips":["Wire the folder picker result directly into Options.dest; never leave it empty.","Provide a default download directory so dest is never blank.","Validate dest is non-empty and creatable before invoking run."],"tags":["validation","missing-argument","filesystem"],"backgroundTag":"empty-required-field","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}