jackwener/OpenCLI · error · CommandExecutionError

${reason}${detail}

Error message

${reason}${detail}

What it means

The grok ask command throws a CommandExecutionError when sendMessage() fails to submit the prompt into the Grok chat UI — the function returned null/undefined or {ok:false}. The message is the sender's reason plus optional detail, and the SESSION_HINT ('Likely login/auth/challenge/session issue') is attached because a failed send almost always means the persistent browser session is logged out, blocked, or showing a challenge instead of the composer. This is thrown before any waiting for a response, so it reflects message-submission failure, not response timeout.

Source

Thrown at clis/grok/ask.js:59

        const timeoutSeconds = kwargs.timeout || 120;
        const newChat = normalizeBooleanFlag(kwargs.new);

        if (newChat) {
            await startNewChat(page);
        } else {
            await ensureOnGrok(page);
        }

        if (!(await isLoggedIn(page))) {
            throw authRequired();
        }

        const baselineLastAssistantId = await getBaselineLastAssistantId(page);
        const sendResult = await sendMessage(page, prompt);
        if (!sendResult || !sendResult.ok) {
            const reason = sendResult?.reason || 'Unable to send the prompt to Grok.';
            const detail = sendResult?.detail ? ` ${sendResult.detail}` : '';
            throw new CommandExecutionError(`${reason}${detail}`, SESSION_HINT);
        }

        const result = await waitForAnswer(page, prompt, timeoutSeconds, baselineLastAssistantId);
        if (result.status === 'ok') {
            return [{ response: result.assistant.text }];
        }
        // Partial: streaming was seen but did not stabilize; keep the best-effort
        // text rather than throwing — the caller asked us to wait, not to discard.
        if (result.status === 'partial' && result.assistant) {
            return [{ response: result.assistant.text }];
        }
        throw new TimeoutError('grok ask response', timeoutSeconds);
    },
});

export const __test__ = {
    getBaselineLastAssistantId,
};

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate the grok.com session (run the site's login/auth command or log in in the persistent browser) — a stale or challenged session is the most common cause, per the attached SESSION_HINT.
  2. Re-run with the `--new` flag to start a fresh chat, which avoids a busy composer left over from a still-streaming previous turn.
  3. Check for Cloudflare/human-verification challenges or rate-limit banners on grok.com in the browser session and clear them manually.
  4. Wait and retry later if the free-tier usage cap disabled the send button.
  5. If it persists after re-login, the composer DOM selectors may be outdated — update the sendMessage implementation in clis/grok/utils.js to match the current grok.com markup.

Example fix

// before
const sendResult = await sendMessage(page, prompt);
if (!sendResult || !sendResult.ok) {
    throw new CommandExecutionError(`${reason}${detail}`, SESSION_HINT);
}
// after: start a clean chat and confirm login before sending
await startNewChat(page);
if (!(await isLoggedIn(page))) throw authRequired();
const sendResult = await sendMessage(page, prompt);
if (!sendResult || !sendResult.ok) {
    throw new CommandExecutionError(`${reason}${detail}`, SESSION_HINT);
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const [{ response }] = await run('grok', 'ask', { prompt });
} catch (e) {
  if (e instanceof CommandExecutionError && /login|auth|challenge|session/i.test(String(e.hint ?? e.message))) {
    await run('grok', 'login');          // refresh the browser session, then retry once
    return await run('grok', 'ask', { prompt, new: true });
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `grok ask "..."` when: (1) isLoggedIn(page) passed but the composer element disappeared before/while typing; (2) the send button or Enter-key submission failed because the page rendered a Cloudflare/X challenge or an upgrade/paywall modal; (3) the send button is disabled (Grok is mid-response from a previous turn, or a usage/rate limit banner blocks sending); (4) sendMessage returned null because a DOM selector for the textarea/composer changed or the chat area never loaded.

Common situations: A stale persistent browser session whose cookies expired so grok.com serves a login redirect; Cloudflare bot challenges after an IP/VPN change; Grok free-tier message limit reached so the composer is disabled; Grok shipping a DOM change that breaks the composer selectors; another chat still streaming, leaving the send control disabled.

Related errors


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