jackwener/OpenCLI · error · CommandExecutionError
Twitter device-follow response was missing the expected time
Error message
Twitter device-follow response was missing the expected timeline/globalObjects shape.
What it means
After a successful fetch, the command runs parseDeviceFollow to extract tweets from the timeline/globalObjects structure. If that shape is absent (parser returns falsy), it throws CommandExecutionError because x.com returned JSON that does not match the expected device-follow notification payload.
Source
Thrown at clis/twitter/device-follow.js:173
} catch (e) {
return { errorKind: 'exception', detail: String(e && e.message || e) };
}
}`);
if (data?.errorKind === 'non_json') {
throw new CommandExecutionError(`Twitter device-follow returned non-JSON response: ${data.detail || 'unknown parse error'}`);
}
if (data?.errorKind === 'exception') {
throw new CommandExecutionError(`Twitter device-follow fetch failed: ${data.detail || 'unknown error'}`);
}
if (data?.error) {
if (data.error === 401 || data.error === 403) {
throw new AuthRequiredError('x.com', `Twitter device-follow returned HTTP ${data.error}`);
}
throw new CommandExecutionError(describeTwitterApiError('device_follow', data.error));
}
const parsed = parseDeviceFollow(data, new Set());
if (!parsed) {
throw new CommandExecutionError('Twitter device-follow response was missing the expected timeline/globalObjects shape.');
}
if (parsed.malformedEntries > 0 || parsed.unmatchedTweetEntries > 0) {
throw new CommandExecutionError('Twitter device-follow entries could not be joined to tweet/user objects.');
}
if (parsed.rows.length === 0) {
throw new EmptyResultError('twitter device-follow', 'No device-follow notification tweets found.');
}
const rows = parsed.rows;
const trimmed = rows.slice(0, limit);
return applyTopByEngagement(trimmed, kwargs['top-by-engagement']);
},
});
export const __test__ = {
buildDeviceFollowUrl,
extractEntries,
joinEntryToTweet,
shapeRow,View on GitHub (pinned to 49907e53dc)
Solutions
- Update/reinstall the CLI in case a newer version parses the new schema
- Dump the raw response and compare it against the expected timeline/globalObjects shape
- Confirm the authenticated account actually has device-follow notifications enabled
- Check for reports of x.com API schema changes if this starts failing consistently
Defensive patterns
Strategy: try-catch
Validate before calling
// No caller-side pre-check; ensure auth first so the payload is the real one
const cookies = await page.getCookies({ url: 'https://x.com' });
if (!cookies.some((c) => c.name === 'ct0')) throw new Error('log in first'); Type guard
function hasTimelineShape(data) {
return !!data && typeof data === 'object' &&
('timeline' in data || 'globalObjects' in data);
} Try / catch
try {
await cli.twitter.deviceFollow();
} catch (e) {
if (e instanceof CommandExecutionError && /timeline\/globalObjects shape/.test(e.message)) {
console.error('x.com response schema changed — update the CLI.');
process.exitCode = 1;
} else throw e;
} Prevention
- Keep the CLI updated — x.com changes its GraphQL payload format over time
- Capture the raw response when debugging to diff against the expected shape
- Confirm the account has device-follow data before assuming parser failure
- Report persistent schema errors upstream with the raw payload
When it happens
Trigger: The GraphQL endpoint responds 200 with JSON that lacks the timeline/globalObjects envelope — e.g. an empty body, a different instruction format after a Twitter frontend change, or a soft-error JSON object without the usual error field.
Common situations: Twitter silently changing its GraphQL response schema; a logged-in-but-restricted session returning an alternate payload; hitting a variant endpoint that returns a new response format the parser doesn't know.
Related errors
- Failed to parse 12306 station_name.js: no station records fo
- Twitter device-follow entries could not be joined to tweet/u
- 12306 ${endpoint} returned an unexpected payload shape
- Ctrip flight API returned a malformed batchSearch payload
- Ctrip flight API returned malformed itinerary at index ${ind
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/108773aa36d4d6f1.
Report an issue: GitHub.