jackwener/OpenCLI · warning · EmptyResultError

@${username} has no media

Error message

@${username} has no media

What it means

After pagination completes with zero collected media items, the command throws EmptyResultError `@<username> has no media` with detail noting the account may be private, suspended, or simply have no media posts. This distinguishes a legitimately empty result from a failure.

Source

Thrown at clis/twitter/download.js:408

        try {
          const r = await fetch("${url}", { headers: ${headers}, credentials: 'include' });
          if (!r.ok) return { ok: false, status: r.status };
          return { ok: true, payload: await r.json() };
        } catch (err) {
          return { ok: false, error: err?.message ?? String(err) };
        }
        }`)));
        const { items, nextCursor } = parseUserMedia(data, seen);
        all.push(...items);
        hasMorePages = Boolean(nextCursor);
        if (!nextCursor) break;
        if (nextCursor === cursor) {
            throw new CommandExecutionError('Twitter UserMedia pagination returned the same cursor twice');
        }
        cursor = nextCursor;
    }

    if (all.length === 0) throw new EmptyResultError(`@${username} has no media`, 'Account may be private, suspended, or have no media posts');
    if (all.length < limit && hasMorePages) {
        throw new CommandExecutionError(`Twitter UserMedia pagination reached the ${MAX_PAGINATION_PAGES}-page safety cap before collecting ${limit} media items`);
    }

    const trimmed = all.slice(0, limit);
    return downloadTwitterMedia(trimmed, {
        output,
        subdir: username,
        cookies: formatCookieHeader(cookies),
        browserCookies: cookies,
        filenamePrefix: username,
        ytdlpExtraArgs: ['--merge-output-format', 'mp4'],
    });
}

async function downloadSingleTweet(page, tweetUrl, output) {
    const target = parseTweetUrl(tweetUrl);
    await page.goto(target.url);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the account has media posts by browsing https://x.com/<username>/media
  2. Ensure your browser session follows/can view the account if it is private
  3. If media visibly exists but none is found, update the CLI so parseUserMedia matches current response shape
Defensive patterns

Strategy: validation

Validate before calling

const hasMedia = await checkProfileMediaTab(username); // visit x.com/<u>/media first
if (!hasMedia) {
  console.log('Account has no downloadable media; skipping');
  return [];
}

Try / catch

try {
  await cmd();
} catch (err) {
  if (err.name === 'EmptyResultError') {
    return []; // legitimately no media — treat as success in pipelines
  }
  throw err;
}

Prevention

When it happens

Trigger: The target account exists (rest_id resolved) but every parsed UserMedia page yields zero media entities: account with no tweets containing media, protected account visible only to followers, suspended mid-flow, or parseUserMedia filters dropping everything.

Common situations: Querying a text-only account expecting images/videos; following a private account from a session that isn't authorized; account got suspended between lookup and media fetch; media parse logic outdated after x.com UI/GraphQL changes.

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 jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/1c6e2e96f1b9449a. Report an issue: GitHub.