{"record":{"id":"41ab0fac4689ae62","repo":"tonhowtf/omniget","slug":"escolha-ao-menos-um-formato-substack","errorCode":null,"errorMessage":"escolha ao menos um formato","messagePattern":"escolha ao menos um formato","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/blogs/substack.rs","lineNumber":390,"sourceCode":"    let v = fetcher\n        .get_json(\"https://substack.com/api/v1/subscriptions\")\n        .await?;\n    let subs = parse_subscriptions(&v);\n    if subs.is_empty() {\n        return Err(anyhow!(\n            \"a conta logada não tem nenhuma assinatura ativa (ou a sessão expirou)\"\n        ));\n    }\n    Ok(subs)\n}\n\npub async fn run(opts: &Options, progress: ProgressFn) -> Result<ArchiveResult> {\n    let dest = opts.dest.trim();\n    if dest.is_empty() {\n        return Err(anyhow!(\"escolha a pasta de destino\"));\n    }\n    if !opts.markdown && !opts.html && !opts.json {\n        return Err(anyhow!(\"escolha ao menos um formato\"));\n    }\n    let root = PathBuf::from(dest);\n    std::fs::create_dir_all(&root)?;\n\n    let domains: Vec<String> = COOKIE_DOMAINS.iter().map(|d| d.to_string()).collect();\n    let fetcher = Fetcher::new(opts.delay_ms, opts.session_netscape.as_deref(), &domains)?;\n\n    // Lista de publicações: o que o usuário digitou tem precedência; vazio\n    // significa \"as minhas assinaturas\".\n    let targets: Vec<Subscription> = if opts.publications.is_empty() {\n        crate::core::tools::report(\n            &progress,\n            ID,\n            \"discover\",\n            0,\n            None,\n            Some(\"assinaturas\".into()),\n        );","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/blogs/substack.rs#L372-L408","documentation":"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).","triggerScenarios":"Calling run(&opts, progress) with an Options struct where markdown == false && html == false && json == false.","commonSituations":"UI checkboxes all left unchecked; options restored from saved settings that lost their booleans; caller constructed Options::default() where all format flags are false.","solutions":["Enable at least one of opts.markdown, opts.html or opts.json before calling run","Default the UI to a sensible preset (e.g. markdown on)","Validate the combination in the caller and surface the requirement before invoking run"],"exampleFix":"// before\nlet opts = Options { dest: dest.into(), markdown: false, html: false, json: false, .. };\n// after\nlet opts = Options { dest: dest.into(), markdown: true, html: false, json: true, .. };","handlingStrategy":"validation","validationCode":"if !(opts.markdown || opts.html || opts.json) {\n    anyhow::bail!(\"at least one output format must be selected\");\n}","typeGuard":"fn has_format(opts: &Options) -> bool { opts.markdown || opts.html || opts.json }","tryCatchPattern":null,"preventionTips":["Provide non-default format flags when constructing Options","Constrain the UI so at least one format checkbox is always on","Add a constructor/builder for Options that enforces the format invariant"],"tags":["validation","substack","rust","options"],"backgroundTag":"missing-required-option","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}