jackwener/OpenCLI · error · CommandExecutionError
LinkedIn messaging API returned a conversation without threa
Error message
LinkedIn messaging API returned a conversation without thread id
What it means
While walking included entities, each com.linkedin.messenger.Conversation must expose a backendUrn of the form urn:li:messagingThread:<id>. If stripping the prefix yields an empty threadId, parseConversations throws CommandExecutionError because thread_id is the primary key for every returned row and its messaging URL.
Source
Thrown at clis/linkedin/inbox.js:92
const participantInfo = (p) => {
if (!p) return { name: '', kind: '' };
const pt = p.participantType || {};
if (pt.organization && pt.organization.name) return { name: norm(pt.organization.name.text), kind: 'organization' };
if (pt.member) {
const fn = pt.member.firstName && pt.member.firstName.text;
const ln = pt.member.lastName && pt.member.lastName.text;
return { name: norm([fn, ln].filter(Boolean).join(' ')), kind: 'member' };
}
if (pt.agent && pt.agent.name) return { name: norm(pt.agent.name.text), kind: 'agent' };
return { name: '', kind: '' };
};
const entries = [];
for (const conv of included) {
if (!conv || conv.$type !== 'com.linkedin.messenger.Conversation') continue;
const threadId = String(conv.backendUrn || '').replace(/^urn:li:messagingThread:/, '');
if (!threadId) {
throw new CommandExecutionError('LinkedIn messaging API returned a conversation without thread id');
}
const others = [];
let counterpartyKind = '';
for (const urn of conv['*conversationParticipants'] || []) {
const p = byUrn.get(urn);
if (!p) continue;
if (mailboxUrn && p.hostIdentityUrn === mailboxUrn) continue; // exclude the inbox owner
const info = participantInfo(p);
if (info.name) {
others.push(info.name);
if (!counterpartyKind) counterpartyKind = info.kind;
}
}
const msgUrns = (conv.messages && conv.messages['*elements']) || [];
const lastMsg = byUrn.get(msgUrns[0]);
let preview = lastMsg && lastMsg.body ? norm(lastMsg.body.text) : '';View on GitHub (pinned to 49907e53dc)
Solutions
- Update the CLI — maintainers may add a skip-rule for URN types that cannot yield a thread id.
- Retry after reloading /messaging/; placeholder entities from a partial sync usually disappear.
- Locally change the throw to `continue` so conversations without backendUrn are skipped instead of aborting the whole listing.
- Capture the offending conversation entity and report it so the URN parsing regex can be widened.
Example fix
// before
if (!threadId) {
throw new CommandExecutionError('LinkedIn messaging API returned a conversation without thread id');
}
// after
if (!threadId) continue; // skip system/sponsored conversations without a messagingThread URN Defensive patterns
Strategy: type-guard
Validate before calling
function hasThreadUrn(conv) {
return conv && conv.$type === 'com.linkedin.messenger.Conversation' &&
typeof conv.backendUrn === 'string' && conv.backendUrn.startsWith('urn:li:messagingThread:');
}
// filter before parsing: entities.filter(hasThreadUrn) Type guard
function isParsableConversation(entity) {
return Boolean(entity && entity.$type === 'com.linkedin.messenger.Conversation' &&
/^urn:li:messagingThread:.+/.test(String(entity.backendUrn || '')));
} Try / catch
try {
const convs = await opencli.linkedin.inbox({ limit: 40 });
} catch (e) {
if (/conversation without thread id/.test(e.message || '')) {
console.warn('Inbox contained a conversation with no messagingThread URN; retrying.');
return opencli.linkedin.inbox({ limit: 40 });
}
throw e;
} Prevention
- Skip non-standard conversation types (sponsored/system) when processing raw entities.
- Widen URN parsing if LinkedIn changes the messagingThread namespace.
- Handle partial-sync placeholder entities by retrying after a reload.
- Keep fixtures updated with all conversation $types your account can return.
When it happens
Trigger: A conversation entity in normalized.included has no backendUrn (or one with an unexpected URN namespace), which can occur for special/system conversations, sponsored threads, or after a LinkedIn URN format change.
Common situations: LinkedIn introducing new conversation types (InMail campaigns, support threads) lacking messagingThread backendUrns; URN prefix change from urn:li:messagingThread: to a new namespace; partially synced inbox returning placeholder conversation entities.
Related errors
- LinkedIn messaging API returned malformed normalized payload
- LinkedIn connection miniProfile field ${field} was malformed
- LinkedIn connections returned an element without a miniProfi
- LinkedIn connections API returned a malformed payload: missi
- LinkedIn jobs preferences returned malformed preferences pay
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/72c7fb5753574f5b.
Report an issue: GitHub.