jackwener/OpenCLI · error · CommandExecutionError
Could not resolve article ${tweetId} to a tweet ID. The arti
Error message
Could not resolve article ${tweetId} to a tweet ID. The article page may not contain a linked tweet. What it means
The twitter article command resolves an X article (long-form post) to its linked tweet before fetching it. An in-page script attempts to extract the tweet id from the article page; if the resolved id is missing or not a string, a CommandExecutionError is thrown because X articles do not always embed a tweet link. The command can only proceed when a concrete tweet id exists.
Source
Thrown at clis/twitter/article.js:53
await page.wait(3);
const resolvedId = await page.evaluate(`
(function() {
var links = document.querySelectorAll('a[href*="/status/"]');
for (var i = 0; i < links.length; i++) {
var m = links[i].href.match(/\\/status\\/(\\d+)/);
if (m) return m[1];
}
var og = document.querySelector('meta[property="og:url"]');
if (og && og.content) {
var m2 = og.content.match(/\\/status\\/(\\d+)/);
if (m2) return m2[1];
}
return null;
})()
`);
const resolvedTweetId = unwrapBrowserResult(resolvedId);
if (!resolvedTweetId || typeof resolvedTweetId !== 'string') {
throw new CommandExecutionError(`Could not resolve article ${tweetId} to a tweet ID. The article page may not contain a linked tweet.`);
}
tweetId = resolvedTweetId;
}
// Navigate to the tweet page for cookie context
await page.goto(`https://x.com/i/status/${tweetId}`);
await page.wait(3);
// Read CSRF token directly from the cookie store via CDP — zero page.evaluate round-trip
const cookies = await page.getCookies({ url: 'https://x.com' });
const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;
if (!ct0)
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
const queryId = await resolveTwitterQueryId(page, 'TweetResultByRestId', TWEET_RESULT_BY_REST_ID_QUERY_ID);
const rawResult = unwrapBrowserResult(await page.evaluate(`
async () => {
const tweetId = ${JSON.stringify(tweetId)};
const ct0 = ${JSON.stringify(ct0)};
const bearer = ${JSON.stringify(TWITTER_BEARER_TOKEN)};View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the article actually contains a linked tweet (open it on x.com and check)
- Re-check the article id/tweetId argument for typos or truncation
- Retry later if X's page markup changed — adapter query scripts may need updating upstream
- If a tweet link exists but isn't found, report/update resolveTwitterQueryId scripts or extract the id manually and use the tweet command
Defensive patterns
Strategy: try-catch
Type guard
function resolvedTweetIdIsUsable(v) { return typeof v === 'string' && v.length > 0 && /^\d+$/.test(v); } Try / catch
try {
await articleCmd({ tweetId });
} catch (err) {
if (err.message.includes('Could not resolve article')) {
console.error('Article has no linked tweet — open it on x.com to verify, or pass the tweet id directly');
} else throw err;
} Prevention
- Verify the article page actually links to a tweet before automating
- Double-check article ids for typos/truncation
- Keep the adapter's page scripts updated after X markup changes
- Fall back to the plain tweet command when the tweet id is known
When it happens
Trigger: Passing an article id whose page's DOM/state does not contain a linked tweet — the browser evaluate returns null or a non-string and the guard rejects it.
Common situations: Articles that are pure long-form posts with no embedded tweet, X rendering changes that move/remove the tweet link, deleting the associated tweet after the article was published, or passing a truncated/incorrect article id.
Related errors
- Douyin search extraction failed: ${error instanceof Error ?
- No profile found for: ${author}
- Could not load Google Scholar profile for: ${author}
- No papers found for: ${data.name || author}
- Google Scholar search returned an unexpected payload shape
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8caf71f8e71d1350.
Report an issue: GitHub.