jackwener/OpenCLI · error · CommandExecutionError
${label} returned an unexpected response
Error message
${label} returned an unexpected response What it means
This CommandExecutionError is thrown by fetchSalesnavJson when the API response neither required auth nor yielded JSON — i.e. result.error is set or result.json is missing. The detail includes the error key plus up to 500 chars of the raw text so the caller can see what actually came back.
Source
Thrown at clis/linkedin/salesnav-inbox.js:128
if (!res.ok) return { error: 'HTTP ' + res.status, status: res.status, text, json };
return { status: res.status, json };
} catch (e) {
return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };
}
})()`;
}
export async function getCsrf(page) {
const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });
const jsession = cookies.find((c) => c.name === 'JSESSIONID')?.value;
if (!jsession) throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.');
return jsession.replace(/^\"|\"$/g, '');
}
export async function fetchSalesnavJson(page, csrf, url, label) {
const result = unwrapEvaluateResult(await page.evaluate(fetchJsonScript(url, csrf)));
if (result?.authRequired) throw new AuthRequiredError(LINKEDIN_DOMAIN, `${label} authentication failed (HTTP ${result.status || 'auth_required'}).`);
if (result?.error || !result?.json) throw new CommandExecutionError(`${label} returned an unexpected response`, `${result?.error || 'no_json'}\n${normalizeWhitespace(result?.text || '').slice(0, 500)}`);
return result.json;
}
export async function fetchInboxRows(page, { limit = DEFAULT_LIMIT, maxPages = 30 } = {}) {
const csrf = await getCsrf(page);
const rows = [];
const seen = new Set();
let pageStartsAt = '';
let pagesFetched = 0;
let hasMorePages = false;
while (rows.length < limit && pagesFetched < maxPages) {
const json = await fetchSalesnavJson(page, csrf, threadListUrl({ count: PAGE_SIZE, pageStartsAt }), 'Sales Navigator messaging threads API');
pagesFetched += 1;
const pageRows = parseSalesnavThreads(json);
if (pageRows.length === 0) break;
for (const row of pageRows) {
if (seen.has(row.thread_id)) continue;
seen.add(row.thread_id);View on GitHub (pinned to 49907e53dc)
Solutions
- Read the error detail (result.error and first 500 chars of text) to identify the actual response
- Retry the request — transient 5xx/network issues often resolve on retry with backoff
- Verify the endpoint URL is current (Sales Nav API paths change) and the CSRF token was sent correctly
- Check whether an HTML challenge/redirect page is being served and re-authenticate if so
Example fix
// before
const json = await fetchSalesnavJson(page, csrf, url, 'inbox');
// after
let json;
try { json = await fetchSalesnavJson(page, csrf, url, 'inbox'); }
catch (e) { await sleep(2000); json = await fetchSalesnavJson(page, csrf, url, 'inbox'); } Defensive patterns
Strategy: retry
Validate before calling
const probe = await fetchSalesnavJson(page, csrf, healthUrl, 'healthcheck');
if (!probe) throw new Error('Sales Nav endpoint not returning JSON; check session/endpoint'); Type guard
function isJsonResult(r) {
return !!r && typeof r === 'object' && !r.error && 'json' in r && r.json != null;
} Try / catch
try {
const json = await fetchSalesnavJson(page, csrf, url, 'inbox');
} catch (e) {
if (String(e.message).includes('unexpected response')) {
await sleep(2000 * attempt); // backoff, log detail from e
return fetchSalesnavJson(page, csrf, url, 'inbox');
}
throw e;
} Prevention
- Log the embedded raw-text detail to identify HTML/5xx responses
- Retry transient failures with exponential backoff
- Verify endpoint URLs after Sales Nav API updates
- Detect login-challenge HTML in responses and trigger re-auth
When it happens
Trigger: Calling fetchSalesnavJson when the Sales Nav endpoint returns non-JSON (HTML error page, empty body, 5xx text), an in-page fetch exception (network failure, CSP block), or a JSON envelope the script flags as error.
Common situations: LinkedIn serving an HTML error/challenge page; server-side 5xx during the request; wrong endpoint URL producing 404 HTML; browser context blocking the fetch (extensions/CSP); transient network failure inside page.evaluate.
Related errors
- Sales Navigator messaging threads API returned malformed pay
- LinkedIn Learning searchV2 failed: ${result?.error ?? 'no pa
- LinkedIn Learning feedRecommendationGroups failed: ${result?
- LinkedIn messaging API returned an unexpected response:
- Sales Navigator messaging threads API returned malformed thr
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/e7843c6c7c76bab3.
Report an issue: GitHub.