jackwener/OpenCLI · error · CommandExecutionError
CreateList returned malformed JSON payload. Body: ${String(r
Error message
CreateList returned malformed JSON payload. Body: ${String(result.bodyText || '').slice(0, 300)} What it means
This CommandExecutionError is thrown by requireCreateListResult in clis/twitter/list-create.js:52 when the CreateList response had HTTP ok status, but the body could not be parsed as JSON (or parsed to a non-object). The library validates result.bodyJson because every later check (data.list, errors) depends on a parsed object. The first 300 chars of the raw body are included to aid diagnosis.
Source
Thrown at clis/twitter/list-create.js:52
if (modeRaw !== 'public' && modeRaw !== 'private') {
throw new ArgumentError(`Invalid mode: ${JSON.stringify(kwargs.mode)}. Expected "public" or "private".`);
}
return { listName: name, listDescription: description, listMode: modeRaw, privateFlag: modeRaw === 'private' };
}
function requireCreateListResult(result, expectedName, expectedMode) {
if (!result || typeof result !== 'object') {
throw new CommandExecutionError(`Unexpected result from twitter list-create: ${JSON.stringify(result)}`);
}
if (result.httpStatus === 401 || result.httpStatus === 403) {
throw new AuthRequiredError('x.com', `Twitter CreateList returned HTTP ${result.httpStatus}`);
}
if (!result.ok) {
const snippet = String(result.bodyText || '').slice(0, 300);
throw new CommandExecutionError(`HTTP ${result.httpStatus} from CreateList: ${snippet}`);
}
if (!result.bodyJson || typeof result.bodyJson !== 'object') {
throw new CommandExecutionError(`CreateList returned malformed JSON payload. Body: ${String(result.bodyText || '').slice(0, 300)}`);
}
const list = result.bodyJson?.data?.list;
if (!list || typeof list !== 'object') {
const errors = result.bodyJson?.errors;
if (Array.isArray(errors) && errors.length > 0) {
throw new CommandExecutionError(`CreateList failed: ${errors[0].message || JSON.stringify(errors[0])}`);
}
throw new CommandExecutionError(`CreateList returned no list payload. Body: ${String(result.bodyText || '').slice(0, 300)}`);
}
const id = String(list.id_str || list.id || '');
if (!/^\d+$/.test(id)) {
throw new CommandExecutionError('CreateList returned a list payload without a numeric list id.');
}
if (typeof list.name !== 'string' || !list.name.trim()) {
throw new CommandExecutionError('CreateList returned a list payload without a list name.');
}
if (list.name.trim() !== expectedName) {
throw new CommandExecutionError(`CreateList returned name ${JSON.stringify(list.name)}, expected ${JSON.stringify(expectedName)}.`);View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the embedded Body snippet — if it is HTML, you are being served a web page (challenge/maintenance) instead of the API response.
- Re-authenticate the browser session on x.com so Twitter serves API JSON rather than a challenge page.
- Disable or change proxy/VPN settings that may inject or truncate response bodies.
- Retry after a delay if Twitter is under maintenance or degraded.
- If it recurs, update the automation/browser environment so fetch from page context returns the real API payload.
Defensive patterns
Strategy: validation
Validate before calling
// After the call, validate the payload shape before using it:
function hasParseableJsonResult(result) {
return Boolean(result && result.ok && result.bodyJson && typeof result.bodyJson === 'object');
} Type guard
function isParsedJsonObject(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
const row = await opencli twitter list-create name;
} catch (err) {
if (/malformed JSON payload/.test(err.message)) {
// body was HTML/empty — re-auth session or retry; do not parse err.message further
await refreshXSession();
} else throw err;
} Prevention
- Keep the automation browser session authenticated so x.com does not serve challenge/maintenance HTML with 200
- Avoid proxies/VPNs that may inject or truncate response bodies
- Retry transiently — a single malformed body is often a degraded-backend blip
- Check status.x.com before running bulk list operations
When it happens
Trigger: Twitter returns HTTP 2xx but with a non-JSON body: an HTML error/interstitial page (e.g. anti-bot challenge or maintenance page served with 200), an empty body, or a truncated response captured by page.evaluate.
Common situations: x.com serving a login/challenge HTML page with 200 status instead of JSON; Twitter maintenance windows returning HTML; proxy/VPN injecting content; network interruption truncating the response so JSON.parse fails.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- CreateList failed: ${errors[0].message || JSON.stringify(err
- CreateList returned no list payload. Body: ${String(result.b
- ${probe.detail}
- ${label} returned invalid JSON
- ${label} returned malformed JSON: ${err?.message ?? err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/388ca95421b4c7a2.
Report an issue: GitHub.