jackwener/OpenCLI · error · CommandExecutionError

Upwork search state (window.__NUXT__.state.jobsSearch) was n

Error message

Upwork search state (window.__NUXT__.state.jobsSearch) was not present within 15s

What it means

A CommandExecutionError thrown when the Browser Bridge poll completes but window.__NUXT__.state.jobsSearch never appeared within the 15s timeout (payload.ready false). The page loaded enough to not redirect or challenge, but the SSR/hydration state for the jobs search never materialized. The library gives up after 15 seconds rather than hanging.

Source

Thrown at clis/upwork/search.js:94

                    jobsPresent: !!(state && Object.prototype.hasOwnProperty.call(state, 'jobs')),
                    jobs: state ? state.jobs : undefined,
                    paging: state && state.paging ? state.paging : null,
                    status: state ? state.status : null,
                };
            })()`));
        }
        catch (e) {
            throw new CommandExecutionError(`Failed to read Upwork search state: ${e?.message ?? e}`, 'The Nuxt state global was not reachable; try again after opening Upwork in the connected browser.');
        }

        if (payload?.onLogin) {
            throw new AuthRequiredError('upwork.com', 'Upwork redirected to login. Open https://www.upwork.com in the connected browser and sign in, then retry.');
        }
        if (payload?.challenge) {
            throw new CommandExecutionError('Upwork served a Cloudflare challenge page', 'Open https://www.upwork.com in the connected browser and clear the challenge, then retry.');
        }
        if (!payload?.ready) {
            throw new CommandExecutionError('Upwork search state (window.__NUXT__.state.jobsSearch) was not present within 15s', 'The page may not have finished hydrating, or the SSR state shape may have changed.');
        }
        if (!isPlainObject(payload)) {
            throw new CommandExecutionError('Upwork search returned an unexpected Browser Bridge payload shape');
        }
        if (!payload.jobsPresent || !Array.isArray(payload.jobs)) {
            throw new CommandExecutionError('Upwork search state had an unexpected jobs shape; expected window.__NUXT__.state.jobsSearch.jobs to be an array.');
        }

        const jobs = payload.jobs;
        if (jobs.length === 0) {
            throw new EmptyResultError('upwork search', `No Upwork jobs matched "${query}"${location ? ` in ${location}` : ''}`);
        }

        const offset = (pageNum - 1) * perPage;
        const rows = jobsToListRows(jobs, { offset, limit: perPage });
        if (rows.length === 0) {
            throw new CommandExecutionError('Upwork search results did not include any job with a valid ciphertext id; cannot produce round-trippable detail rows.');
        }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command once the page has fully finished loading in the connected browser.
  2. Verify the connected tab is actually on an Upwork jobs search results page.
  3. If it reproduces on a fully loaded page, inspect window.__NUXT__.state in DevTools to see if the jobsSearch key moved - update the CLI's expectations if Upwork changed shape.
  4. Improve network/CPU conditions (close heavy tabs, faster connection) and increase patience before retrying.

Example fix

// before
await cli.search('vue developer') // throws: state not present within 15s
// after
await page.waitForFunction(() => window.__NUXT__?.state?.jobsSearch, { timeout: 30000 }); // or retry the command after full load
await cli.search('vue developer')
Defensive patterns

Strategy: retry

Validate before calling

// wait for hydration before invoking, or confirm the page is a search results page
await page.waitForFunction(() => !!(window.__NUXT__ && window.__NUXT__.state), { timeout: 30000 });
if (!location.pathname.includes('/jobs')) throw new Error('Navigate to an Upwork jobs search page first');

Type guard

function isNuxtStateReady(win) {
  return !!(win && win.__NUXT__ && win.__NUXT__.state &&
    typeof win.__NUXT__.state === 'object');
}

Try / catch

try {
  rows = await cli.search(query);
} catch (e) {
  if (String(e.message).includes('was not present within 15s')) {
    await waitForHydration(60000); // give the page more time
    rows = await cli.search(query); // retry once
  } else throw e;
}

Prevention

When it happens

Trigger: Running upwork search against a page that hydrates slowly, a page where Upwork changed the __NUXT__ state shape so jobsSearch no longer exists, or a search URL that renders no jobsSearch state (e.g. not actually on a search results page).

Common situations: Slow network or heavy page causing hydration past 15s; an Upwork frontend update renaming/moving jobsSearch in the Nuxt payload; landing on a login-adjacent or error page that still isn't a challenge; CPU-starved browser taking long to hydrate.

Related errors


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