jackwener/OpenCLI · error · CommandExecutionError

Click on account button "${label}" failed

Error message

Click on account button "${label}" failed

What it means

In the Qoder 'account' command, after detecting (or being given) the username label, the adapter clicks it with clickByTextScript([label], {exact:true, maxLen:60}). If that click reports {ok:false}, it throws CommandExecutionError(`Click on account button "${label}" failed`). Detection succeeded but the exact-text click could not find/click the matching button.

Source

Thrown at clis/qoder/ui.js:278

            label = await evaluateQoder(page, `(() => {
        ${IS_VISIBLE_JS}
        const btns = Array.from(document.querySelectorAll('button')).filter(isVisible);
        const known = new Set(['Pin', 'Copy', 'New Quest', 'Search', 'Settings', 'View all', 'Knowledge', 'Marketplace', 'Credits Usage', 'Open Editor', 'Add Workspace', 'More Actions', 'Send message', 'Prompt Enhance', 'Voice input', 'button']);
        const candidate = btns.find((b) => {
          const tx = (b.innerText || '').trim();
          if (!tx || tx.length > 30 || tx.includes('⌘') || known.has(tx)) return false;
          if (/^(New|Open|Add|Save|Edit|Cancel|OK|Close)/.test(tx)) return false;
          return true;
        });
        return candidate ? (candidate.innerText || '').trim() : '';
      })()`);
        }
        if (!label) {
            throw new CommandExecutionError('No account button detected. Pass --username <name> explicitly.', '');
        }
        // Click the username button
        const clickRes = await evaluateQoder(page, clickByTextScript([label], { exact: true, maxLen: 60 }));
        if (!clickRes?.ok) throw new CommandExecutionError(`Click on account button "${label}" failed`, '');
        await page.wait(0.5);
        const items = requireArrayResult(await evaluateQoder(page, `(() => {
      ${IS_VISIBLE_JS}
      const popovers = Array.from(document.querySelectorAll('[role="menu"], [role="dialog"], [class*="popover"i], [class*="dropdown"i]')).filter(isVisible)
        .filter((el) => { const r = el.getBoundingClientRect(); return r.width < 500 && r.height < 600; });
      if (!popovers.length) return [];
      const pop = popovers[popovers.length - 1];
      return Array.from(pop.querySelectorAll('button, [role="menuitem"], a'))
        .filter(isVisible)
        .map((b) => (b.innerText || b.textContent || '').trim().replace(/\\s+/g, ' '))
        .filter(Boolean);
    })()`), 'qoder account');
        try { await page.evaluate(`document.body.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));`); } catch {}
        const rows = [{ Field: 'Username', Value: label }];
        (items || []).slice(0, 20).forEach((item, i) => {
            rows.push({ Field: `Item[${i + 1}]`, Value: item });
        });
        return rows;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Pass a --username value exactly as displayed in the UI (same case, no truncation), or shorten to the displayed form.
  2. Fall back to substring matching (exact:false) when exact click fails.
  3. Re-detect and click in one pass to avoid re-render races.
  4. Increase maxLen if the display name is longer than 60 characters.
  5. Inspect the button's innerText via CDP DevTools and use that exact string.

Example fix

// before
clickByTextScript([label], { exact: true, maxLen: 60 })
// after: fallback to substring match
let clickRes = await evaluateQoder(page, clickByTextScript([label], { exact: true, maxLen: 60 }));
if (!clickRes?.ok) clickRes = await evaluateQoder(page, clickByTextScript([label], { exact: false, maxLen: 120 }));
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the username matches the exact UI text before clicking
function normalizeUsername(name) {
  const s = String(name).replace(/\s+/g, ' ').trim();
  if (!s || s.length > 60) {
    throw new Error('Username must be non-empty and <= 60 chars, exactly as shown in the Qoder UI.');
  }
  return s;
}

Type guard

function isValidUsernameLabel(label) {
  return typeof label === 'string' && label.trim().length > 0 && label.length <= 60;
}

Try / catch

try {
  await cli.run(['qoder', 'account', '--username', label]);
} catch (e) {
  if (String(e.message).includes('Click on account button')) {
    // retry with the exact innerText copied from the Qoder UI
    console.error('Use the exact display name as rendered (whitespace/emoji included).');
  } else throw e;
}

Prevention

When it happens

Trigger: The label scraped from a candidate button does not exactly equal any clickable element's trimmed innerText (detection and click use different matching: detection is heuristic, click uses exact match with maxLen 60); username longer than 60 chars; whitespace/emoji differences in the rendered text; UI re-rendered between detection and click.

Common situations: Username containing trailing whitespace, newlines, or an avatar glyph so exact match fails; long display names truncated in UI but passed in full via --username; Qoder re-render replacing the element between the two evaluate calls.

Related errors


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