tonhowtf/omniget · error

um carrossel tem de 2 a 20 arquivos

Error message

um carrossel tem de 2 a 20 arquivos

What it means

For kind == 'carousel', publish_web enforces Instagram's sidecar limits: between 2 and 20 files. Requests outside this range fail with 'um carrossel tem de 2 a 20 arquivos' (a carousel has 2 to 20 files).

Solutions

  1. Send kind 'photo' when there is exactly one file
  2. Truncate or split selections larger than 20 items before building the request
  3. Validate carousel file count in the UI before invoking publish_web

Example fix

// before
publish({ kind: 'carousel', files: [singleFile] })
// after
const kind = files.length === 1 ? 'photo' : 'carousel';
if (files.length > 20) throw new Error('um carrossel tem de 2 a 20 arquivos');
Defensive patterns

Strategy: validation

Validate before calling

if (kind === 'carousel' && (files.length < 2 || files.length > 20)) {
  throw new Error('um carrossel tem de 2 a 20 arquivos');
}

Type guard

function validCarousel(files) { return Array.isArray(files) && files.length >= 2 && files.length <= 20; }

Try / catch

try { await publish(req) } catch (e) { if (String(e).includes('2 a 20 arquivos')) { fixKindOrTruncate(req); } else { throw e; } }

Prevention

When it happens

Trigger: Calling publish_web with kind 'carousel' and req.files.len() == 0, 1, or > 20.

Common situations: User selects a single image but the UI sends kind 'carousel' instead of 'photo', or a bulk selection exceeds Instagram's 20-item limit.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/instagram/publish.rs:460

                        return Ok(result_of(&json));
                    }
                    Ok(json) => last = Some(anyhow!("configure: {}", json)),
                    Err(IgError::Other(e))
                        if e.contains("Transcode")
                            || e.contains("not ready")
                            || e.contains("202") =>
                    {
                        last = Some(anyhow!(e));
                    }
                    Err(e) => return Err(m(e)),
                }
                tokio::time::sleep(std::time::Duration::from_secs(4 + attempt * 3)).await;
            }
            Err(last.unwrap_or_else(|| anyhow!("o Instagram nao confirmou o video")))
        }
        "carousel" => {
            if req.files.len() < 2 || req.files.len() > 20 {
                return Err(anyhow!("um carrossel tem de 2 a 20 arquivos"));
            }
            let total = req.files.len() as u64 + 1;
            let sidecar_id = upload_id();
            let mut children: Vec<Value> = Vec::new();
            for (i, f) in req.files.iter().enumerate() {
                report("upload", i as u64, total);
                let path = Path::new(f);
                let uid = format!("{}{}", upload_id(), i);
                let is_video = matches!(
                    path.extension()
                        .and_then(|e| e.to_str())
                        .map(|e| e.to_lowercase())
                        .as_deref(),
                    Some("mp4" | "mov" | "m4v" | "webm")
                );
                if is_video {
                    let (w, h, dur) = probe_video(path).await?;
                    let bytes = tokio::fs::read(path).await?;

View on GitHub (pinned to 8600b91f42)