jackwener/OpenCLI · error · CommandExecutionError

Twitter/X profile link probe returned a malformed href

Error message

Twitter/X profile link probe returned a malformed href

What it means

readScreenName reads the profile link (a[data-testid="AppTabBar_Profile_Link"]) href via page.evaluate and passes it through unwrapTwitterEvaluateResult. If the bridge returns a defined value that is not a string or null, the DOM probe result is deemed malformed and this CommandExecutionError is thrown. Called by readSettledScreenName and username flows.

Source

Thrown at clis/twitter/auth.js:31

}

function unwrapTwitterEvaluateResult(value, label) {
  if (value && typeof value === 'object' && !Array.isArray(value) && 'session' in value) {
    if (typeof value.session === 'string' && Object.prototype.hasOwnProperty.call(value, 'data')) {
      return value.data;
    }
    throw new CommandExecutionError(`Twitter/X ${label} returned a malformed Browser Bridge envelope`);
  }
  return value;
}

async function readScreenName(page) {
  const href = unwrapTwitterEvaluateResult(await page.evaluate(`() => {
    const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
    return link ? link.getAttribute('href') : null;
  }`), 'profile link probe');
  if (href !== null && typeof href !== 'string') {
    throw new CommandExecutionError('Twitter/X profile link probe returned a malformed href');
  }
  return normalizeTwitterScreenName(typeof href === 'string' ? href : '');
}

/**
 * Right after an account switch the home surface keeps showing the previous
 * account for a few seconds, so a single read misreports it (#2252); trust
 * the handle only once it holds across three polls.
 */
async function readSettledScreenName(page) {
  const samples = [];
  for (let poll = 0; poll < SCREEN_NAME_POLLS; poll += 1) {
    samples.push(await readScreenName(page));
    if (poll < SCREEN_NAME_POLLS - 1) {
      await page.sleep(SCREEN_NAME_POLL_SECONDS);
    }
  }
  const tail = samples.slice(-SCREEN_NAME_AGREEMENTS);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Reload x.com and retry; the selector usually returns a proper href once the page is stable.
  2. Re-authenticate so the logged-in nav bar (which contains the profile link) renders.
  3. Check for conflicting browser extensions that mutate DOM attributes on x.com.
  4. Update the CLI/extension pair if Twitter shipped a DOM change.

Example fix

// before
const href = unwrapTwitterEvaluateResult(await page.evaluate(probeSrc), 'profile link probe');
// after
const href = unwrapTwitterEvaluateResult(await page.evaluate(probeSrc), 'profile link probe');
if (href !== null && typeof href !== 'string') {
  console.warn('href probe returned', typeof href); // log before throwing
}
Defensive patterns

Strategy: type-guard

Validate before calling

await page.waitForSelector('a[data-testid="AppTabBar_Profile_Link"]', { timeout: 5000 }).catch(() => null);

Type guard

function isHref(value) {
  return value === null || typeof value === 'string';
}

Try / catch

const href = unwrapTwitterEvaluateResult(await page.evaluate(probeSrc), 'profile link probe');
if (!isHref(href)) throw new Error('href probe returned ' + typeof href);

Prevention

When it happens

Trigger: The href probe returns a non-string, non-null value — e.g. the envelope unwrap yielded a number, object, or array instead of the link's href attribute.

Common situations: Browser Bridge envelope corruption (related to 4003), a page where a custom element or extension replaced the profile link attribute type, or Twitter DOM experiments changing what the selector matches.

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/72a3b9ef07889421. Report an issue: GitHub.