jackwener/OpenCLI · error · CommandExecutionError

Malformed Twitter follower: missing screen_name

Error message

Malformed Twitter follower: missing screen_name

What it means

This error is thrown by extractFollower when a follower entry parsed from Twitter's Followers GraphQL timeline has __typename 'User' but no screen_name in either the core or legacy blocks. The library treats a User entry without a handle as malformed because the screen_name column is the primary key of the output contract (columns: ['screen_name','name','bio']); it cannot emit a dedupable row without it. It surfaces as a CommandExecutionError rather than silently skipping the entry.

Source

Thrown at clis/twitter/followers.js:15

import { ArgumentError, AuthRequiredError, EmptyResultError, CommandExecutionError, TimeoutError } from '@jackwener/opencli/errors';
import { cli, Strategy } from '@jackwener/opencli/registry';
import { looksLikePrivateTwitterTimeline, normalizeTwitterGraphqlPayload, normalizeTwitterScreenName, unwrapBrowserResult } from './shared.js';

const MAX_PAGINATION_PAGES = 100;
const CAPTURE_TIMEOUT_SECONDS = 10;

function extractFollower(result) {
    if (!result || result.__typename !== 'User')
        return null;
    const core = result.core || {};
    const legacy = result.legacy || {};
    const screenName = core.screen_name || legacy.screen_name || '';
    if (!screenName) {
        throw new CommandExecutionError('Malformed Twitter follower: missing screen_name');
    }
    return {
        screen_name: screenName,
        name: core.name || legacy.name || '',
        bio: result.profile_bio?.description || legacy.description || '',
    };
}

function parseFollowers(value) {
    const data = normalizeTwitterGraphqlPayload(value);
    const users = [];
    let nextCursor = null;
    let bottomTerminated = false;
    const instructions = data?.data?.user?.result?.timeline_v2?.timeline?.instructions
        || data?.data?.user?.result?.timeline?.timeline?.instructions
        || [];
    for (const instruction of instructions) {
        if (instruction?.type === 'TimelineTerminateTimeline' && instruction.direction === 'Bottom') {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the library / shared.js payload normalization to the current Twitter GraphQL shape so core.screen_name or legacy.screen_name is found
  2. Re-run the command — transient malformed entries often disappear on retry
  3. Check whether the target account is suspended/restricted and try a different target user
  4. File a bug with the raw captured response so the parser can be extended

Example fix

// before
const screenName = core.screen_name || legacy.screen_name || '';
if (!screenName) {
    throw new CommandExecutionError('Malformed Twitter follower: missing screen_name');
}
// after (skip instead of failing the whole run)
const screenName = core.screen_name || legacy.screen_name || result.screen_name || '';
if (!screenName) return null;
Defensive patterns

Strategy: try-catch

Validate before calling

const result = entry?.itemContent?.user_results?.result;
if (result?.__typename === 'User' && !(result.core?.screen_name || result.legacy?.screen_name)) {
  console.warn('skipping follower without screen_name');
}

Type guard

function hasScreenName(r) {
  return !!r && r.__typename === 'User' &&
    typeof (r.core?.screen_name || r.legacy?.screen_name) === 'string' &&
    (r.core?.screen_name || r.legacy?.screen_name).length > 0;
}

Try / catch

try {
  const rows = await opencli.twitter.followers(user, { limit });
} catch (err) {
  if (err.message.includes('Malformed Twitter follower')) {
    // schema drift: retry, update library, or fall back to partial data
  } else throw err;
}

Prevention

When it happens

Trigger: A Followers GraphQL response contains a user- entry whose itemContent.user_results.result has __typename 'User' but both core.screen_name and legacy.screen_name are absent/empty — typically when Twitter ships a new GraphQL payload shape or returns a partially redacted/suspended user object.

Common situations: Twitter/X changes its GraphQL response schema (A/B tests, API versions); a follower account is suspended or restricted so fields are stripped; a proxy or mock returns truncated user objects during testing.

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/1425b8cda28e114a. Report an issue: GitHub.