jackwener/OpenCLI · error · CommandExecutionError

Twitter profile response for @${screenName} is malformed

Error message

Twitter profile response for @${screenName} is malformed

What it means

CommandExecutionError thrown by mapTwitterProfileResult when the raw API result for a profile is not a plain object — X returned something unexpected (an error payload, empty body, or guest-mode redirect) instead of the user object.

Source

Thrown at clis/twitter/profile.js:43

function isPlainObject(value) {
    return value != null && typeof value === 'object' && !Array.isArray(value);
}

function stringField(value) {
    return typeof value === 'string' ? value : '';
}

function countField(...values) {
    for (const value of values) {
        if (typeof value === 'number' && Number.isFinite(value))
            return value;
    }
    return 0;
}

export function mapTwitterProfileResult(result, screenName) {
    if (!isPlainObject(result)) {
        throw new CommandExecutionError(`Twitter profile response for @${screenName} is malformed`);
    }
    const hasLegacy = isPlainObject(result.legacy);
    const hasCore = isPlainObject(result.core);
    if (!hasLegacy && !hasCore) {
        throw new CommandExecutionError(`Twitter profile response for @${screenName} is missing profile fields`);
    }
    const legacy = hasLegacy ? result.legacy : {};
    const core = hasCore ? result.core : {};
    if (!stringField(core.screen_name) && !stringField(legacy.screen_name) && !stringField(core.name) && !stringField(legacy.name) && !stringField(core.created_at) && !stringField(legacy.created_at)) {
        throw new CommandExecutionError(`Twitter profile response for @${screenName} is missing profile identity fields`);
    }
    const location = isPlainObject(result.location) ? result.location : {};
    const expandedUrl = stringField(result.website?.url) || stringField(legacy.entities?.url?.urls?.[0]?.expanded_url);
    return [{
        screen_name: stringField(core.screen_name) || stringField(legacy.screen_name) || screenName,
        name: stringField(core.name) || stringField(legacy.name),
        bio: stringField(result.profile_bio?.description) || stringField(legacy.description),
        location: stringField(location.location) || stringField(legacy.location),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the browser session is logged in; re-run `opencli login`
  2. Retry after a delay — rate limiting is a common cause of malformed payloads
  3. Test whether the profile exists by visiting https://x.com/<handle> in the browser session
  4. If the handle is valid and you're logged in but this persists, X likely changed the response shape; report/update the mapper
Defensive patterns

Strategy: validation

Validate before calling

function isValidHandle(h) {
  return typeof h === 'string' && /^@?[A-Za-z0-9_]{1,15}$/.test(h.trim());
}
if (!isValidHandle(username)) throw new Error('invalid handle');

Type guard

const isPlainObject = (v) =>
  v !== null && typeof v === 'object' && !Array.isArray(v);

Try / catch

try {
  const profile = await opencli('twitter profile', { username });
} catch (e) {
  if (e.name === 'CommandExecutionError' && /is malformed/.test(e.message)) {
    await relogin(); // likely rate-limited or logged-out payload
    return opencli('twitter profile', { username });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the `twitter profile` command where the UserByScreenName GraphQL response (or page-scraped equivalent) is not an object: error JSON, null, HTML error page parsed as string, or rate-limit response.

Common situations: X rate-limits the session and returns an error object; logged-out/guest fetch returns an HTML page; X API shape changes; account shadow-banned so the user lookup errors.

Understand the failure class

Related errors


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