jackwener/OpenCLI · error · CommandExecutionError
CreateList returned no list payload. Body: ${String(result.b
Error message
CreateList returned no list payload. Body: ${String(result.bodyText || '').slice(0, 300)} What it means
This CommandExecutionError is thrown by requireCreateListResult in clis/twitter/list-create.js:60 when the CreateList response is ok JSON but lacks a data.list object and contains no errors array either. The library requires bodyJson.data.list to exist to confirm the list was created. This indicates an unexpected/empty success payload from Twitter.
Source
Thrown at clis/twitter/list-create.js:60
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)}.`);
}
const modeValue = typeof list.mode === 'string' ? list.mode : '';
if (!modeValue) {
throw new CommandExecutionError('CreateList returned a list payload without list mode.');
}
const mode = /private/i.test(modeValue) ? 'private' : 'public';
if (mode !== expectedMode) {
throw new CommandExecutionError(`CreateList returned mode ${mode}, expected ${expectedMode}.`);View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the embedded Body snippet to see what Twitter actually returned in place of data.list.
- Check whether the list was actually created on x.com (the mutation can succeed server-side while returning an unexpected payload) before retrying to avoid duplicates.
- If the response shape changed, update requireCreateListResult to read the new path for the created list object.
- Retry after a short delay if Twitter's backend was degraded — an empty data payload can be transient.
- Disable browser extensions/scripts that might rewrite fetch responses inside the automated page.
Example fix
// before (old response path) const list = result.bodyJson?.data?.list; // after (if Twitter moved the created entity in the response) const list = result.bodyJson?.data?.list ?? result.bodyJson?.data?.create_list;
Defensive patterns
Strategy: validation
Validate before calling
// After the call, guard the expected response shape:
function hasListPayload(result) {
const list = result?.bodyJson?.data?.list;
return Boolean(list && typeof list === 'object');
} Type guard
function isCreatedListPayload(bodyJson) {
return Boolean(
bodyJson && typeof bodyJson === 'object' &&
bodyJson.data && typeof bodyJson.data === 'object' &&
bodyJson.data.list && typeof bodyJson.data.list === 'object'
);
} Try / catch
try {
const row = await opencli twitter list-create name;
} catch (err) {
if (/returned no list payload/.test(err.message)) {
// check x.com whether the list was actually created before retrying
const exists = await checkListExistsOnX(name);
if (!exists) retryCreationOnce();
} else throw err;
} Prevention
- Check x.com for the list before retrying — the mutation may have succeeded server-side despite the empty payload, and a blind retry creates duplicates
- Watch for Twitter response schema changes to data.list and update the extraction path
- Disable browser extensions that rewrite fetch responses in the automated page
- Avoid running bulk creations while Twitter is degraded (empty data payloads can be transient)
When it happens
Trigger: Response like { data: {} }, { data: { list: null } }, or an empty JSON object with HTTP 2xx — a successful transport but no list entity returned, e.g. the mutation silently failed or Twitter changed the CreateList response shape (renamed/moved data.list).
Common situations: Twitter changing the GraphQL response schema (data.list moved or renamed), silent server-side failure returning empty data, response intercepted/modified by browser extensions or automation scripts, partial responses from a degraded Twitter backend.
Related errors
- Twitter UserMedia returned malformed user result
- Twitter UserMedia returned malformed timeline instructions
- Malformed Twitter follower: missing screen_name
- CreateList returned malformed JSON payload. Body: ${String(r
- CreateList failed: ${errors[0].message || JSON.stringify(err
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2f6141da98d01ce4.
Report an issue: GitHub.