jackwener/OpenCLI · warning · CommandExecutionError

Copy button not visible

Error message

Copy button not visible

What it means

When copy-message runs with click-button=true, it invokes clickBySvgNameScript('Copy') on the last assistant turn; if the in-page script cannot find/click a Copy button, CommandExecutionError is thrown. The message (or clickRes.reason) indicates the copy control was not present or not clickable at that moment.

Source

Thrown at clis/kimi/chat.js:346

    browser: true,
    siteSession: 'persistent',
    navigateBefore: false,
    args: [
        { name: 'conv', required: false, help: 'Chat id or URL (navigates there before reading)' },
        { name: 'click-button', type: 'boolean', default: false, help: 'Also click in-UI Copy button (writes to clipboard)' },
    ],
    columns: CHAT_COLUMNS,
    func: async (page, kwargs) => {
        await maybeNavigateConv(page, kwargs?.conv);
        const turns = await readKimiTurns(page);
        const assistantTurns = turns.filter((t) => t.role === 'Assistant');
        if (!assistantTurns.length) {
            throw new EmptyResultError('kimi copy-message', 'No assistant message visible.');
        }
        const last = assistantTurns[assistantTurns.length - 1];
        if (kwargs?.['click-button'] === true || kwargs?.['click-button'] === 'true') {
            const clickRes = await page.evaluate(clickBySvgNameScript('Copy'));
            if (!clickRes?.ok) throw new CommandExecutionError(clickRes?.reason || 'Copy button not visible', '');
        }
        return [
            { Field: 'Length', Value: String((last.text || '').length) + ' chars' },
            { Field: 'ClipboardClicked', Value: (kwargs?.['click-button'] === true || kwargs?.['click-button'] === 'true') ? 'yes' : 'no' },
            { Field: 'Text', Value: last.text || '' },
        ];
    },
});

// -------- regenerate --------
cli({
    site: 'kimi',
    name: 'regenerate',
    access: 'write',
    description: 'Click Refresh (Kimi\'s regenerate button) on the last assistant message. Pass --conv <id> to target a specific chat.',
    domain: KIMI_DOMAIN,
    strategy: Strategy.COOKIE,
    browser: true,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Omit click-button and just read the returned Text field — the command already returns the full assistant message, so DOM copy is usually unnecessary.
  2. Hover/focus the last assistant message before clicking (e.g. move mouse to the turn) so the Copy button renders.
  3. Wait until the response finishes streaming, then retry.
  4. Update the SVG name ('Copy') if the Kimi UI changed the icon.

Example fix

// before
await cli('kimi', 'copy-message', { 'click-button': true });
// after
const out = await cli('kimi', 'copy-message'); // no DOM click needed
const text = out.find(r => r.Field === 'Text').Value;
Defensive patterns

Strategy: fallback

Type guard

function clickOk(res) { return !!res && res.ok === true; }

Try / catch

try {
  return await cli('kimi', 'copy-message', { 'click-button': true });
} catch (e) {
  if (/Copy button not visible/i.test(e.message)) {
    // DOM copy unavailable; use returned text instead
    return await cli('kimi', 'copy-message');
  }
  throw e;
}

Prevention

When it happens

Trigger: Copy button only renders on hover/focus of the assistant message; kwargs['click-button'] is truthy but no response is hovered; Kimi renamed the Copy SVG icon or moved it behind an overflow menu.

Common situations: Headless automation where hover-dependent buttons never appear; Kimi UI updates relocating the copy action; calling click-button on a still-streaming response whose action bar hasn't rendered.

Related errors


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