{"record":{"id":"adf447e6c88bea7e","repo":"jackwener/OpenCLI","slug":"upwork-detail-returned-an-unexpected-browser-bridg","errorCode":null,"errorMessage":"Upwork detail returned an unexpected Browser Bridge payload shape","messagePattern":"Upwork detail returned an unexpected Browser Bridge payload shape","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/upwork/detail.js","lineNumber":89,"sourceCode":"                    onLogin,\n                    challenge,\n                    job: s.job ? JSON.parse(JSON.stringify(s.job)) : null,\n                    buyer: s.buyer ? JSON.parse(JSON.stringify(s.buyer)) : null,\n                };\n            })()`));\n        }\n        catch (e) {\n            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.');\n        }\n\n        if (payload?.onLogin) {\n            throw new AuthRequiredError('upwork.com', 'Upwork redirected to login. Open https://www.upwork.com in the connected browser and sign in, then retry.');\n        }\n        if (payload?.challenge) {\n            throw new CommandExecutionError('Upwork served a Cloudflare challenge page', 'Open https://www.upwork.com in the connected browser and clear the challenge, then retry.');\n        }\n        if (!isPlainObject(payload)) {\n            throw new CommandExecutionError('Upwork detail returned an unexpected Browser Bridge payload shape');\n        }\n        if (!payload?.ready || !payload.job) {\n            throw new EmptyResultError('upwork detail', `No Upwork job posting found for id \"${id}\" (may be closed, expired, or private)`);\n        }\n        if (!isPlainObject(payload.job)) {\n            throw new CommandExecutionError('Upwork job-detail store had an unexpected job shape; expected an object.');\n        }\n\n        const job = payload.job;\n        const returnedCiphertext = String(job?.ciphertext ?? '').trim();\n        if (returnedCiphertext && returnedCiphertext !== id) {\n            throw new CommandExecutionError(`Upwork job-detail store returned ciphertext \"${returnedCiphertext}\" while reading \"${id}\".`);\n        }\n        const buyer = payload.buyer || {};\n        const stats = buyer?.stats || {};\n        const location = buyer?.location || {};\n        const category = job?.category?.name || '';\n        const skills = formatSkills(job);","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/upwork/detail.js#L71-L107","documentation":"After the login/challenge checks, the command validates that the Browser Bridge payload is a plain object via isPlainObject. If the evaluate returned null, an array, a string, or otherwise non-object data, it throws CommandExecutionError reporting the unexpected payload shape, preventing downstream property access on garbage.","triggerScenarios":"The in-page extraction IIFE returns something other than a plain object — evaluate cancelled mid-navigation, script exception produced undefined, a Browser Bridge serialization mismatch, or page context returned a primitive.","commonSituations":"Page navigated/reloaded during evaluate so the result is undefined/null; a version mismatch between CLI extraction script and the injected bridge; Upwork page erroring before the store reader builds its result object; extensions interfering with page scripts.","solutions":["Retry with the Upwork job page fully loaded and idle (no pending navigation).","Update the library — mismatched Browser Bridge/injection versions are a frequent cause of shape drift.","Open the job page manually in the connected browser to confirm it renders normally before running the command.","If reproducible on a healthy page, report/inspect: Upwork may have changed its store structure and the extractor needs updating.","Restart the browser bridge connection to rule out stale sessions returning empty results."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"await page.goto(jobUrl, { waitUntil: 'networkidle' });\nif (!page.url().includes('upwork.com')) throw new Error('Navigation left Upwork; payload shape cannot be trusted');","typeGuard":"function isPlainObject(v) {\n  if (v === null || typeof v !== 'object') return false;\n  const proto = Object.getPrototypeOf(v);\n  return proto === Object.prototype || proto === null;\n}","tryCatchPattern":"try {\n  const detail = await fetchUpworkJobDetail(id);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /unexpected Browser Bridge payload shape/.test(e.message)) {\n    await page.waitForNetworkIdle();\n    return fetchUpworkJobDetail(id); // retry once after the page settles\n  }\n  throw e;\n}","preventionTips":["Run fetches only when the page is idle — mid-navigation evaluate often returns null/undefined.","Keep CLI and browser-bridge/injection versions in sync; shape mismatches cause this error.","Pre-validate results with an isPlainObject guard before accessing properties.","If persistent on a healthy page, suspect an Upwork site change and update the extractor."],"tags":["upwork","payload-shape","browser-bridge","validation"],"backgroundTag":"unexpected-payload-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}