jackwener/OpenCLI · error · CommandExecutionError
Upwork served a Cloudflare challenge page
Error message
Upwork served a Cloudflare challenge page
What it means
If the Vuex-store payload carries a challenge flag, Upwork served a Cloudflare challenge/bot-check page instead of the app. The command throws CommandExecutionError telling the user to clear the challenge manually, since automation cannot (and should not) solve it.
Source
Thrown at clis/upwork/detail.js:86
const s = window.$nuxt.$store.state.jobDetails;
return {
ready,
onLogin,
challenge,
job: s.job ? JSON.parse(JSON.stringify(s.job)) : null,
buyer: s.buyer ? JSON.parse(JSON.stringify(s.buyer)) : null,
};
})()`));
}
catch (e) {
throw new CommandExecutionError(`Failed to read Upwork job-detail store: ${e?.message ?? e}`, 'The Vuex store 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 (!isPlainObject(payload)) {
throw new CommandExecutionError('Upwork detail returned an unexpected Browser Bridge payload shape');
}
if (!payload?.ready || !payload.job) {
throw new EmptyResultError('upwork detail', `No Upwork job posting found for id "${id}" (may be closed, expired, or private)`);
}
if (!isPlainObject(payload.job)) {
throw new CommandExecutionError('Upwork job-detail store had an unexpected job shape; expected an object.');
}
const job = payload.job;
const returnedCiphertext = String(job?.ciphertext ?? '').trim();
if (returnedCiphertext && returnedCiphertext !== id) {
throw new CommandExecutionError(`Upwork job-detail store returned ciphertext "${returnedCiphertext}" while reading "${id}".`);
}
const buyer = payload.buyer || {};
const stats = buyer?.stats || {};View on GitHub (pinned to 49907e53dc)
Solutions
- Open https://www.upwork.com in the connected browser and manually complete the Cloudflare challenge, then retry.
- Switch off VPN/proxy or use a residential IP; avoid running from flagged datacenter IPs.
- Slow down request frequency / add delays between Upwork commands to avoid tripping rate-based challenges.
- Use a regular (non-headless) browser profile with normal history/fingerprint.
- If challenges persist, wait and retry later — IP reputation may recover.
Defensive patterns
Strategy: retry
Validate before calling
const res = await fetch('https://www.upwork.com/robots.txt');
if (res.status === 403 || res.status === 503) throw new Error('Cloudflare is challenging this IP; clear it in the browser first'); Try / catch
try {
const detail = await fetchUpworkJobDetail(id);
} catch (e) {
if (e instanceof CommandExecutionError && /Cloudflare challenge/.test(e.message)) {
console.log('Open https://www.upwork.com in the connected browser, solve the challenge, then retry after a delay.');
await sleep(60_000);
} else throw e;
} Prevention
- Avoid datacenter/VPN IPs with poor reputation; prefer residential connections.
- Throttle Upwork requests — aggressive scraping triggers challenges.
- Use a normal, non-headless browser profile with realistic fingerprints.
- After a challenge, solve it manually in the browser before resuming automation.
When it happens
Trigger: Fetching Upwork job details when Cloudflare intercepts the request — suspicious IP reputation, datacenter/VPN IP, too-frequent scraping, or first visit from a new browser fingerprint — producing a challenge page whose store payload sets challenge:true.
Common situations: Running the CLI from a VPS/cloud server IP; aggressive repeated scraping triggering rate-based challenges; VPN/proxy usage; browser lacking typical fingerprints (headless); shared IP previously flagged.
Related errors
- Upwork served a Cloudflare challenge page
- Upwork served a Cloudflare challenge page
- Indeed served a Cloudflare challenge page
- Indeed served a Cloudflare challenge page
- 12306 queryByTrainNo returned non-JSON body
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5a5d89bcc94a533c.
Report an issue: GitHub.