jackwener/OpenCLI · error · CommandExecutionError

twitter_collection_invalid_timestamp

twitter_collection_invalid_timestamp

Error message

twitter_collection_invalid_timestamp: post ${post.id}

What it means

parseCreatedAt validates each post's created_at field: it must be a non-empty string parseable to a valid Date. Posts without a usable timestamp cannot be compared against the 'until' cutoff, so completion of the collection can't be proven and the library throws this error naming the offending post id.

Source

Thrown at clis/twitter/collection.js:240

        ) {
            nextCursor = value.value;
        }
        if (Array.isArray(value)) {
            for (const item of value) visit(item);
            return;
        }
        for (const child of Object.values(value)) {
            if (child && typeof child === 'object') visit(child);
        }
    };
    for (const instructions of instructionSets) visit(instructions);
    return [posts, nextCursor];
}

function parseCreatedAt(post) {
    const parsed = new Date(post.created_at);
    if (typeof post.created_at !== 'string' || !post.created_at || Number.isNaN(parsed.getTime())) {
        throw new CommandExecutionError(`twitter_collection_invalid_timestamp: post ${post.id}`);
    }
    return parsed;
}

function completedReceipt(stopReason, until, pagesFetched, oldestSeenAt) {
    return {
        completed: true,
        stop_reason: stopReason,
        requested_until: until.toISOString(),
        pages_fetched: pagesFetched,
        oldest_seen_at: oldestSeenAt ? oldestSeenAt.toISOString() : null,
    };
}

async function paginateCollection({ until, limit, maxPages = MAX_USER_TWEETS_PAGES, fetchPage, wait }) {
    const seen = new Set();
    const seenCursors = new Set();
    const posts = [];

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Skip or whitelist promoted/ad entries and tombstones in the visit() walker before calling parseCreatedAt.
  2. Log the offending post.id and its raw object to confirm which entry type lacks created_at.
  3. Add a fallback timestamp source (e.g. tweet.core.legacy.created_at or sort index) if X moved the field.
  4. Update the library if X changed the legacy payload shape.
  5. Retry pagination — transient timeline injections usually disappear on the next page fetch.

Example fix

// before
const createdAt = parseCreatedAt(post);
// after
if (!post?.created_at || Number.isNaN(new Date(post.created_at).getTime())) {
  console.warn('skipping post without timestamp', post?.id);
  continue;
}
const createdAt = parseCreatedAt(post);
Defensive patterns

Strategy: type-guard

Validate before calling

const bad = posts.filter(p => typeof p?.created_at !== 'string' || !p.created_at || Number.isNaN(new Date(p.created_at).getTime()));
if (bad.length) console.warn('posts lacking valid created_at:', bad.map(p => p.id));

Type guard

function hasValidCreatedAt(post) {
  return typeof post?.created_at === 'string' && post.created_at.length > 0
    && !Number.isNaN(new Date(post.created_at).getTime());
}

Try / catch

try {
  const createdAt = parseCreatedAt(post);
} catch (err) {
  if (String(err.message).startsWith('twitter_collection_invalid_timestamp')) {
    const id = String(err.message).split('post ')[1];
    console.warn('skipping malformed post', id);
  } else throw err;
}

Prevention

When it happens

Trigger: A UserTweets entry whose tweet.legacy.created_at is missing, empty, or malformed (e.g. ad/promoted entries, tombstones reshaped into post objects, or X renaming legacy fields).

Common situations: Promoted/ad tweets injected into the timeline lacking legacy.created_at; X schema change renaming created_at; posts from retweets/quote cards with truncated legacy objects; account locale changes altering date format unexpectedly.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/a176d25f605ef289. Report an issue: GitHub.