jackwener/OpenCLI · error · CommandExecutionError
LinkedIn messengerMessages API returned a malformed page wra
Error message
LinkedIn messengerMessages API returned a malformed page wrapper.
What it means
Thrown by parseThreadPages when an individual page entry is not a plain object with a string url property. Each page must be the { url, json } wrapper the fetch script builds; anything else means the caller passed data of an unexpected shape or the fetch script's contract changed.
Source
Thrown at clis/linkedin/thread-snapshot.js:208
|| !/^messengerMessages\.[a-f0-9]+$/i.test(url.searchParams.get('queryId') || '')
|| !threadId
|| !decoded.includes(threadId)) {
throw new CommandExecutionError('LinkedIn messengerMessages discovery returned an unsafe or mismatched URL.');
}
}
return apiUrls;
}
function parseThreadPages(pages) {
if (!Array.isArray(pages) || pages.length === 0) {
throw new CommandExecutionError('LinkedIn messengerMessages API returned no pages.');
}
const entities = new Map();
const apiUrls = [];
for (const page of pages) {
if (!page || typeof page !== 'object' || Array.isArray(page) || typeof page.url !== 'string') {
throw new CommandExecutionError('LinkedIn messengerMessages API returned a malformed page wrapper.');
}
const normalized = page.json;
if (!normalized || typeof normalized !== 'object' || Array.isArray(normalized)) {
throw new CommandExecutionError('LinkedIn messengerMessages API returned a malformed normalized payload.');
}
if (Array.isArray(normalized.errors) && normalized.errors.length > 0) {
throw new CommandExecutionError('LinkedIn messengerMessages GraphQL returned errors.');
}
if (!Array.isArray(normalized.included)) {
throw new CommandExecutionError('LinkedIn messengerMessages payload is missing the included entity array.');
}
const data = normalized.data?.data;
if (!data || typeof data !== 'object' || Array.isArray(data)) {
throw new CommandExecutionError('LinkedIn messengerMessages payload is missing normalized data.');
}
const container = Object.entries(data).find(([key, value]) => (
/^messengerMessages/i.test(key)
&& valueView on GitHub (pinned to 49907e53dc)
Solutions
- Pass the untouched { pages } array returned by buildFetchThreadPagesScript into parseThreadPages — do not unwrap or rebuild the wrappers.
- Validate each page ({ url: string, json: object }) in the caller before parsing.
- If the fetch script was customized, restore the { url, json } contract or update parseThreadPages accordingly.
Example fix
// before: unwrapping json and losing the wrapper
const pages = responses.map((r) => r.json);
parseThreadPages(pages);
// after: keep the wrapper shape
const pages = responses.map((r) => ({ url: r.url, json: r.json }));
parseThreadPages(pages); Defensive patterns
Strategy: type-guard
Validate before calling
if (!pages.every((p) => p && typeof p === 'object' && !Array.isArray(p) && typeof p.url === 'string')) {
throw new Error('Each page must be a { url: string, json: object } wrapper');
} Type guard
function isPageWrapper(p) {
return Boolean(p) && typeof p === 'object' && !Array.isArray(p)
&& typeof p.url === 'string'
&& Boolean(p.json) && typeof p.json === 'object' && !Array.isArray(p.json);
} Try / catch
try {
const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });
} catch (err) {
if (err.message.includes('malformed page wrapper')) {
// stop passing unwrapped/reshaped fetch results; use the library's pipeline end to end
} else throw err;
} Prevention
- Feed parseThreadPages only the raw { pages } output of the fetch script.
- Do not unwrap { url, json } wrappers into bare JSON before parsing.
- Type-check intermediate results when adapting the pipeline in custom scripts.
When it happens
Trigger: A pages element is null/undefined, an array, a primitive, or an object whose .url is not a string — e.g. pages was constructed manually, or the fetch script was updated to return a different wrapper shape.
Common situations: Developer reused parseThreadPages with raw JSON responses instead of { url, json } wrappers; a forked/modified fetch script renamed or dropped the url field; caching layers serialized/deserialized pages into arrays or null entries.
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
- LinkedIn jobs preferences returned malformed preferences pay
- LinkedIn jobs preferences returned malformed alerts payload
- LinkedIn people search returned malformed extraction payload
- LinkedIn people search returned malformed row at index ${ind
- LinkedIn people search returned row without stable profile i
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/6456efcc53116385.
Report an issue: GitHub.