jackwener/OpenCLI · error · CommandExecutionError

BOSS detail page did not expose a complete job posting

Error message

BOSS detail page did not expose a complete job posting

What it means

captureJobDetail throws CommandExecutionError('BOSS detail page did not expose a complete job posting') when two navigation attempts and five render-poll passes each fail to produce a row with name, description, and company — and the page is NOT a login wall. The library requires all three fields to consider the posting readable; incomplete DOM means BOSS changed its layout, the job is gone, or rendering never completed.

Source

Thrown at clis/boss/detail.js:138

    await navigateTo(page, 'https://www.zhipin.com/web/geek/jobs', 2);
    for (let navigationAttempt = 0; navigationAttempt < 2; navigationAttempt++) {
        await navigateTo(page, url, 5);
        for (let attempt = 0; attempt < 5; attempt++) {
            try {
                const domRow = await readRenderedPage(page, jobId);
                if (domRow?.name && domRow?.description && domRow?.company) return domRow;
            } catch { /* wait for a complete render */ }
            if (attempt < 4) await page.wait(1);
        }
    }
    // The retry loop above swallows every read error, so without this check a
    // session that got bounced to the login wall reports "incomplete posting".
    // The API path this command replaced classified that as AuthRequiredError
    // via assertOk; keep that signal rather than losing it to the UI rewrite.
    if (await isLoginWall(page)) {
        throw new AuthRequiredError(BOSS_DOMAIN, 'BOSS redirected the job detail page to the login flow');
    }
    throw new CommandExecutionError('BOSS detail page did not expose a complete job posting');
}

async function isLoginWall(page) {
    try {
        return await page.evaluate(`
            (() => {
                const href = window.location.href || '';
                if (/\\/login|\\/user\\/login|passport/.test(href)) return true;
                return !!document.querySelector('.sign-form, .login-card, [class*="login-register"]');
            })()
        `) === true;
    } catch {
        return false;
    }
}
cli({
    site: 'boss',
    name: 'detail',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the security-id against a fresh `opencli boss search` — the job may have been taken down or the id mistyped.
  2. Open the job URL (https://www.zhipin.com/job_detail/<id>.html) in a normal browser to confirm the posting still exists and renders.
  3. Retry later or with a faster network/longer waits; transient render timeouts produce this error.
  4. If the page renders in a browser but the CLI fails, BOSS likely changed DOM classes — update selectors in extractRenderedDetail (clis/boss/detail.js) or upgrade the package.
  5. Try fetching from a different network/IP if risk-control is serving degraded pages.

Example fix

// before
const row = await detail('1aBcD2ef'); // page gone → incomplete posting
// after
const results = await search({ query: 'same role' });
const job = results.find(r => r.name === expectedName);
if (!job) throw new Error('job no longer listed');
const row = await detail(job.security_id); // fresh id
Defensive patterns

Strategy: retry

Validate before calling

// validate the security-id format before calling detail
const jobId = securityId.trim();
if (!/^[A-Za-z0-9_-]+$/.test(jobId)) throw new Error('invalid security-id format');

Type guard

function isAuthRequiredError(e) { return e && (e.name === 'AuthRequiredError' || /login flow/i.test(e.message || '')); }

Try / catch

try {
  const row = await detail(securityId);
} catch (e) {
  if (isCommandExecutionError(e) && /complete job posting/.test(e.message)) {
    await sleep(5000); // transient render delay
    const row2 = await detail(securityId);
    if (row2) return row2;
    throw new Error(`job ${securityId} may be off-market — verify in browser`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Job deleted/expired/unpublished so the page shows an error or skeleton without job content; BOSS DOM restructure breaking the .job-primary/.job-detail selectors; page rendered too slowly even after ~5 waits ×2 navigations; invalid security-id reaching a soft-404 page.

Common situations: Off-market or closed job postings returning empty detail sections; regional/AB-test layouts with different class names; heavy network latency causing the render wait (page.wait(1)) to be insufficient; malformed security-id passing the regex but pointing at a nonexistent job.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/6e46c878ad5a1a64. Report an issue: GitHub.