jackwener/OpenCLI · error · CommandExecutionError
LinkedIn messengerMessages payload is missing a message coll
Error message
LinkedIn messengerMessages payload is missing a message collection.
What it means
Thrown by parseThreadPages when no key under normalized.data.data matches the messengerMessages container shape — an object with a '*elements' (or 'elements') array. This container holds the URNs of the messages in the thread; without it the payload, though otherwise valid, contains no message collection to snapshot.
Source
Thrown at clis/linkedin/thread-snapshot.js:232
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)
&& value
&& typeof value === 'object'
&& !Array.isArray(value)
&& (Array.isArray(value['*elements']) || Array.isArray(value.elements))
));
if (!container) {
throw new CommandExecutionError('LinkedIn messengerMessages payload is missing a message collection.');
}
for (const entity of normalized.included) {
if (!entity || typeof entity !== 'object' || Array.isArray(entity)) {
throw new CommandExecutionError('LinkedIn messengerMessages payload contains a malformed included entity.');
}
if (entity.entityUrn) {
const existing = entities.get(entity.entityUrn);
if (!existing || Object.keys(entity).length > Object.keys(existing).length) {
entities.set(entity.entityUrn, entity);
}
}
}
apiUrls.push(page.url);
}
const ownerUrn = ownerUrnFromApiUrls(apiUrls);
if (!ownerUrn) {
throw new CommandExecutionError('LinkedIn messengerMessages URL is missing the conversation owner identity.');View on GitHub (pinned to 49907e53dc)
Solutions
- Confirm every validated apiUrl is a messengerMessages query (queryId regex) and not another voyager operation.
- Reload the thread and rerun so fresh requests with the correct operation are captured.
- Inspect the data.data keys in devtools; if LinkedIn renamed the container, update the /^messengerMessages/i key test and the '*elements'/'elements' shape check.
- If the thread genuinely has no messages, treat empty threads as a supported case rather than a parse failure.
Example fix
// before: exact key assumption breaks on rename const container = data.messengerMessages; // after: shape-based lookup (as the library does) const container = Object.entries(data).find(([key, value]) => /^messengerMessages/i.test(key) && value && typeof value === 'object' && !Array.isArray(value) && (Array.isArray(value['*elements']) || Array.isArray(value.elements)) );
Defensive patterns
Strategy: validation
Validate before calling
const data = json?.data?.data;
const hasContainer = data && Object.entries(data).some(([k, v]) =>
/^messengerMessages/i.test(k) && v && typeof v === 'object' && !Array.isArray(v)
&& (Array.isArray(v['*elements']) || Array.isArray(v.elements)));
if (!hasContainer) throw new Error('No messengerMessages collection in payload'); Type guard
function isMessageContainer(v) {
return Boolean(v) && typeof v === 'object' && !Array.isArray(v)
&& (Array.isArray(v['*elements']) || Array.isArray(v.elements));
} Try / catch
try {
const snapshot = await cli.linkedin.threadSnapshot({ url: threadUrl });
} catch (err) {
if (err.message.includes('missing a message collection')) {
// confirm the captured URL is a messengerMessages operation; reload and retry
} else throw err;
} Prevention
- Ensure all discovered URLs match the messengerMessages queryId pattern before replay.
- Reload the page before capture so the exact live-app operation is recorded.
- Track LinkedIn API renames of the messengerMessages result key.
- Handle genuinely empty threads as a distinct, expected case.
When it happens
Trigger: Object.entries(data) finds no key where /^messengerMessages/i matches the key AND the value is a non-array object AND value['*elements'] or value.elements is an array — e.g. data.data exists but holds a different operation's result or an empty result object.
Common situations: The replayed URL was a different GraphQL operation (not messengerMessages) that slipped through discovery; LinkedIn renamed the result key after an API update; the server returned an operation object without elements for an empty/deleted thread.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- LinkedIn messengerMessages payload is missing normalized dat
- 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
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/83be7bce2dbf63b7.
Report an issue: GitHub.