jackwener/OpenCLI · error · CommandExecutionError
${context} returned a malformed message.
Error message
${context} returned a malformed message. What it means
requireReplyActionResult validates the object returned from page.evaluate() in the twitter reply flow before it is used. A browser-side result may include a `message` field for error reporting; the library throws this CommandExecutionError when `message` is present and non-null but is not a string (e.g. a number, object, or array). This protects callers from passing a non-string message into error construction or templating, which would produce broken diagnostics.
Source
Thrown at clis/twitter/reply.js:37
// (silent: matched `/status/1234567` on substring `/status/123` and
// accepted any host). parseTweetUrl bubbles ArgumentError on
// malformed/off-domain inputs.
const target = parseTweetUrl(rawUrl);
return `https://x.com/compose/post?in_reply_to=${target.id}`;
}
function isPromiseCollectedError(err) {
const msg = err instanceof Error ? err.message : String(err);
return msg.includes('Promise was collected');
}
function requireReplyActionResult(value, context) {
const result = unwrapBrowserResult(value);
if (!result || typeof result !== 'object' || Array.isArray(result) || typeof result.ok !== 'boolean') {
throw new CommandExecutionError(`${context} returned a malformed result.`);
}
if (Object.prototype.hasOwnProperty.call(result, 'message') && result.message != null && typeof result.message !== 'string') {
throw new CommandExecutionError(`${context} returned a malformed message.`);
}
if (Object.prototype.hasOwnProperty.call(result, 'url') && result.url != null && typeof result.url !== 'string') {
throw new CommandExecutionError(`${context} returned a malformed status url.`);
}
return result;
}
function validateReplyStatusUrl(result) {
if (!result.url) return;
let url;
try {
url = new URL(result.url);
} catch {
throw new CommandExecutionError('Twitter reply completion returned a malformed status url.');
}
const hostname = url.hostname.toLowerCase().replace(/^www\./, '');
const match = url.pathname.match(/^\/([^/]+)\/status\/(\d+)\/?$/);
if (!['x.com', 'twitter.com', 'mobile.twitter.com'].includes(hostname) || !match) {View on GitHub (pinned to 49907e53dc)
Solutions
- Fix the browser-side script to return a string: replace `return { ok: false, message: e }` with `return { ok: false, message: e instanceof Error ? e.message : String(e) }`.
- Check that the evaluate snippet's return object only puts strings into `message`; move structured error data to separate fields.
- If you control the caller, coerce before returning: `message: String(rawMessage)`.
Example fix
// before (inside page.evaluate)
catch (e) {
return { ok: false, message: e };
}
// after
catch (e) {
return { ok: false, message: e instanceof Error ? e.message : String(e) };
} Defensive patterns
Strategy: type-guard
Validate before calling
// After receiving any browser result, before using .message:
if (result.message != null && typeof result.message !== 'string') {
throw new Error('message field must be a string');
} Type guard
function isReplyActionResult(v) {
return !!v && typeof v === 'object' && !Array.isArray(v) &&
typeof v.ok === 'boolean' &&
(v.message == null || typeof v.message === 'string');
} Try / catch
try {
await cli('twitter', 'reply', { url, text });
} catch (e) {
if (String(e.message).includes('returned a malformed message')) {
// treat as a tooling/bridge bug: log the raw result and report
} else throw e;
} Prevention
- Always stringify caught exceptions in page.evaluate snippets: message: e instanceof Error ? e.message : String(e).
- Keep message fields string-only; move structured data to sibling fields.
- Add a unit test asserting evaluate results pass isReplyActionResult.
When it happens
Trigger: The in-page script (reply click, reply text insertion, or submit polling) returns { ok, message: <non-string> } — e.g. `message: e` (an Error object) or `message: errorCode` (a number) instead of `message: e.toString()` / a string literal.
Common situations: Editing or writing a new page.evaluate() snippet inside clis/twitter/reply.js and forgetting to stringify the caught exception; a code change swapping a string message for a structured { code, text } object; serialization quirks where a string becomes a String wrapper object.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ${context} returned a malformed status url.
- Unexpected 12306 probe: ${JSON.stringify(probe)}
- Waiting for 12306 tk auth cookie
- x.com
- Nothing changed. Open the tweet in the browser and retry.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/eb4b8a775298a21f.
Report an issue: GitHub.