{"record":{"id":"754946fcf00d2699","repo":"jackwener/OpenCLI","slug":"twitter-download-target-id","errorCode":null,"errorMessage":"twitter download ${target.id}","messagePattern":"twitter download (.+?)","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/twitter/download.js","lineNumber":453,"sourceCode":"          out.push({ type: 'image', url: src });\n        });\n        document.querySelectorAll('video').forEach(video => {\n          const src = video.src || '';\n          if (src) out.push({ type: 'video', url: src });\n        });\n        document.querySelectorAll('[data-testid=\"videoPlayer\"]').forEach(player => {\n          const tweetLink = player.closest('article')?.querySelector('a[href*=\"/status/\"]');\n          const href = tweetLink?.getAttribute('href') || '';\n          if (href) out.push({ type: 'video-tweet', url: 'https://x.com' + href });\n        });\n        return out;\n      })()\n    `));\n    if (!Array.isArray(items)) {\n        throw new CommandExecutionError('Twitter tweet media extraction returned malformed payload');\n    }\n    if (items.length === 0) {\n        throw new EmptyResultError(`twitter download ${target.id}`, 'No media found in the tweet');\n    }\n    const cookies = await page.getCookies({ domain: 'x.com' });\n    const seen = new Set();\n    const unique = items.filter((m) => {\n        if (seen.has(m.url)) return false;\n        seen.add(m.url);\n        return true;\n    }).map((m) => {\n        return { ...m, tweet_id: target.id };\n    });\n    return downloadTwitterMedia(unique, {\n        output,\n        subdir: 'tweets',\n        cookies: formatCookieHeader(cookies),\n        browserCookies: cookies,\n        filenamePrefix: 'tweet',\n        ytdlpExtraArgs: ['--merge-output-format', 'mp4'],\n    });","sourceCodeStart":435,"sourceCodeEnd":471,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/download.js#L435-L471","documentation":"The `twitter download <tweet-id>` command threw EmptyResultError because its in-page media extraction script returned an array with zero media items. The library throws this when the tweet parsed successfully but contains no downloadable media (images/videos), or when extraction silently found nothing on the live page. It deliberately distinguishes 'no data' from malformed payloads (which raise CommandExecutionError).","triggerScenarios":"Running `opencli twitter download <id>` on a tweet with no media attachments; extraction against a protected/deleted tweet where the DOM renders but yields no media nodes; X UI changes making the extractor's selectors miss media so items.length === 0.","commonSituations":"Passing a tweet ID for a text-only tweet; scraping a protected or age-gated account while logged out; X shipping a redesign that breaks extraction selectors; a rate-limited view of the tweet that omits media.","solutions":["Verify the tweet actually has images or video by opening https://x.com/<user>/status/<id> in a browser.","Log into x.com in the connected browser session so protected/age-gated media is visible, then retry.","Retry with a fresh page load (not a cached or limited view) in case media was not rendered.","If media is visibly present but the error persists, the extraction selectors are likely stale — update the CLI or report the DOM change."],"exampleFix":"// before\nopencli twitter download 1234567890 // text-only tweet\n// after\nopencli twitter download 9876543210 // tweet with attached images/video","handlingStrategy":"validation","validationCode":"// Extracted media array guard before consuming results\nfunction hasMedia(items) {\n  return Array.isArray(items) && items.length > 0 && items.every((m) => typeof m?.url === 'string');\n}\n// Run twitter download only for tweets you know embed media; pre-check the tweet\n// (e.g. oEmbed or the profile page) to confirm media presence before invoking.","typeGuard":"function isMediaItem(m) {\n  return typeof m === 'object' && m !== null && typeof m.url === 'string' && m.url.length > 0;\n}","tryCatchPattern":"try {\n  const rows = await twitterDownload(tweetId);\n} catch (e) {\n  if (e.code === 'EMPTY_RESULT') {\n    // Tweet has no media — skip, don't retry\n    logger.warn(`No media in tweet ${tweetId}, skipping`);\n  } else throw e;\n}","preventionTips":["Only call `twitter download` on tweet IDs known to contain images or video.","Stay logged into x.com in the connected browser so protected media renders.","Treat EMPTY_RESULT as 'skip this tweet', not a failure to retry.","Keep the CLI updated; X DOM changes silently break extraction to zero results."],"tags":["twitter","empty-result","media-extraction","scraping"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}