jackwener/OpenCLI · error · CommandExecutionError
twitter_collection_unresolved_relationship
twitter_collection_unresolved_relationship
Error message
twitter_collection_unresolved_relationship: repost target is unavailable
What it means
When a collected timeline post is a repost, extractRelationship requires the resolved repost target (retweeted_status_result.result) and a concrete post_id. If only an ID stub exists without resolvable content, or the target can't be resolved to a post_id, the library throws rather than emitting a repost entry with an unusable target.
Source
Thrown at clis/twitter/collection.js:126
: contextStatus;
return {
post_id: postId,
author_handle: authorHandle,
author_id: authorId,
url: postId && authorHandle ? `https://x.com/${authorHandle}/status/${postId}` : null,
context_status: resolvedContextStatus,
};
}
function extractRelationship(result) {
const tweet = unwrapTweetResult(result);
const legacy = tweet?.legacy || {};
const repostResult = tweet?.retweeted_status_result?.result || legacy.retweeted_status_result?.result || null;
const repostId = legacy.retweeted_status_id_str || null;
if (repostResult || repostId) {
const target = relationshipTarget(repostResult, repostId, repostResult ? 'complete' : 'unknown');
if (!repostResult || !target.post_id) {
throw new CommandExecutionError('twitter_collection_unresolved_relationship: repost target is unavailable');
}
return { kind: 'repost', target };
}
const quoteResult = tweet?.quoted_status_result?.result || legacy.quoted_status_result?.result || null;
const quoteId = legacy.quoted_status_id_str || null;
if (legacy.is_quote_status || quoteResult || quoteId) {
return {
kind: 'quote',
target: relationshipTarget(quoteResult, quoteId, quoteResult ? 'complete' : 'unavailable'),
};
}
const replyId = legacy.in_reply_to_status_id_str || null;
const replyHandle = normalizeTwitterScreenName(legacy.in_reply_to_screen_name || '') || null;
const replyAuthorId = typeof legacy.in_reply_to_user_id_str === 'string' && legacy.in_reply_to_user_id_str.trim()
? legacy.in_reply_to_user_id_str
: null;
if (replyId || replyHandle || replyAuthorId) {
return {View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run collection — tombstones are sometimes transient; retry after a delay
- Skip or log-and-continue for that tweet if your tooling allows (the error is per-post)
- Check whether the target tweet is deleted/withheld by fetching its ID directly
- Update the CLI — newer X API shapes may need a newer unwrap path
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
function repostTargetAvailable(tweet) {
const legacy = tweet?.legacy || {};
const result = tweet?.retweeted_status_result?.result || legacy.retweeted_status_result?.result;
const id = legacy.retweeted_status_id_str;
return Boolean(result && result?.rest_id) || Boolean(!result && id); // stub-only still fails downstream
} Type guard
function hasResolvableRepost(tweet) {
const r = tweet?.retweeted_status_result?.result ?? tweet?.legacy?.retweeted_status_result?.result;
return r != null && typeof r.rest_id === 'string';
} Try / catch
try {
posts.push(extractCollectionPost(entry, seen));
} catch (err) {
if (String(err.message).startsWith('twitter_collection_unresolved_relationship')) {
console.warn('skipping post with unavailable repost target');
} else throw err;
} Prevention
- Expect tombstones for deleted/withheld repost targets and handle them per-post
- Re-run collections to catch transiently unavailable targets
- Fetch repost target IDs directly to confirm availability before archiving
- Keep the CLI updated for current retweeted_status_result shapes
When it happens
Trigger: A tweet has legacy.retweeted_status_id_str or a retweeted_status_result but the embedded result is missing/tombstoned (deleted or withheld repost target), so target.post_id cannot be built.
Common situations: Archiving timelines where the reposted tweet was deleted or made unavailable after the repost; withheld/geo-blocked content returning tombstone results; X GraphQL payloads omitting retweeted_status_result for older reposts.
Related errors
- twitter_bookmarks_protocol_error
- twitter_bookmarks_repeated_cursor
- twitter_collection_protocol_error
- Twitter device-follow entries could not be joined to tweet/u
- Malformed Twitter following user: missing screen_name
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/080cced49ca314c2.
Report an issue: GitHub.