jackwener/OpenCLI · error · CommandExecutionError
Twitter lists returned an unexpected payload shape
Error message
Twitter lists returned an unexpected payload shape
What it means
This CommandExecutionError is thrown when the Twitter lists management page data fetched via the browser session does not contain the expected instruction payload. The CLI verifies the API/page response contains recognizable lists-management data via getListsManagementInstructions(data) before parsing; if that check fails, the payload shape has drifted from what the parser understands. It indicates a UI/API contract change on Twitter/X (or an intercepted but wrong response), not a user input problem.
Source
Thrown at clis/twitter/lists.js:170
}`);
const queryId = unwrap(queryIdRaw) || LISTS_QUERY_ID;
const headers = JSON.stringify({
'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
'X-Csrf-Token': ct0,
'X-Twitter-Auth-Type': 'OAuth2Session',
'X-Twitter-Active-User': 'yes',
});
const apiUrl = buildUrl(queryId);
const data = await page.evaluate(`async () => {
const r = await fetch(${JSON.stringify(apiUrl)}, { headers: ${headers}, credentials: 'include' });
return r.ok ? await r.json() : { error: r.status };
}`);
if (data?.error) {
throw new CommandExecutionError(describeTwitterApiError('ListsManagementPageTimeline', data.error));
}
const seen = new Set();
if (!getListsManagementInstructions(data)) {
throw new CommandExecutionError('Twitter lists returned an unexpected payload shape');
}
const lists = parseListsManagement(data, seen);
if (lists.length === 0) {
throw new EmptyResultError('twitter lists', 'No owned or subscribed lists found');
}
return lists.slice(0, limit);
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command after logging in fully; ensure the browser session reaches the lists management page, not a login/interstitial.
- Update the opencli twitter CLI to a version matching the current Twitter payload shape (check for package updates/changelog).
- Retry later — Twitter frequently rolls out schema variants; if persistent, file an issue with a redacted captured payload.
- Inspect page.getInterceptedRequests() output to confirm the captured request is the lists-management GraphQL call and not another endpoint.
Example fix
// before
const requests = await page.getInterceptedRequests();
const data = JSON.parse(requests[0].body);
// after — pick the request that actually matches the lists GraphQL operation
const req = requests.find(r => r.url.includes('ListManagement') || r.url.includes('/i/api/graphql/'));
if (!req) throw new CommandExecutionError('Lists GraphQL request not captured');
const data = JSON.parse(req.body); Defensive patterns
Strategy: try-catch
Validate before calling
// best-effort pre-check after capture, before parsing
const data = JSON.parse(req.body);
if (!data || typeof data !== 'object' || !data?.data) {
throw new Error('Captured Twitter lists payload missing expected data field');
} Type guard
function isListsPayload(data) {
return !!data && typeof data === 'object' && (
'data' in data || 'instructions' in data
);
} Try / catch
try {
const lists = await twitterLists({ limit });
render(lists);
} catch (err) {
if (err.message.includes('unexpected payload shape')) {
console.error('Twitter lists schema changed; update the CLI or retry later');
} else throw err;
} Prevention
- Keep the opencli twitter CLI updated to track Twitter payload changes
- Log captured payloads (redacted) so schema drift is diagnosable
- Verify the session is fully logged in before running list commands
When it happens
Trigger: The 'twitter lists' command ran inside a browser session, page.waitForCapture/getInterceptedRequests returned a JSON payload, data.error was absent, but getListsManagementInstructions(data) returned falsy — i.e. the captured GraphQL response lacks the expected instructions/timeline structure that parseListsManagement expects.
Common situations: Twitter/X changed its GraphQL list-management response schema; the CLI captured the wrong network response (e.g. an embed or redirect page); a partial/logged-out render returned HTML instead of JSON; A/B test variants of the lists page ship a different payload.
Related errors
- Unexpected 12306 probe: ${JSON.stringify(probe)}
- Waiting for 12306 tk auth cookie
- Douyin search: unexpected evaluator payload shape
- ${label} returned a malformed payload
- ${label} returned malformed rows
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/b2b5722dc3dcdf2f.
Report an issue: GitHub.