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
- 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.
- Re-run with the `--new` flag to start a fresh chat, which avoids a busy composer left over from a still-streaming previous turn.
- Check for Cloudflare/human-verification challenges or rate-limit banners on grok.com in the browser session and clear them manually.
- Wait and retry later if the free-tier usage cap disabled the send button.
- 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
- Re-authenticate the grok.com session regularly instead of letting cookies lapse.
- Use the --new flag when a previous conversation may still be streaming, to avoid a busy composer.
- Watch for Cloudflare challenges and clear them manually before running scripted commands.
- Track free-tier usage limits and back off when nearing the cap.
- After grok.com UI updates, smoke-test one ask command before batch automation.
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
- LinkedIn messengerMessages API authentication failed: ${fetc
- Upwork redirected to login. Open https://www.upwork.com in t
- Xianyu messages requires a logged-in browser session
- Redirected away from creator center — session may have expir
- Sign in to grok.com in your browser, then retry.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/076380b4f4c7a4df.
Report an issue: GitHub.