{"record":{"id":"fc26e93f130bc545","repo":"jackwener/OpenCLI","slug":"label-unexpected-evaluate-result-shape","errorCode":null,"errorMessage":"${label}: unexpected evaluate result shape","messagePattern":"(.+?): unexpected evaluate result shape","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/qoder/_utils.js","lineNumber":40,"sourceCode":"    if (cs.visibility === 'hidden' || cs.display === 'none' || cs.opacity === '0') return false;\n    return true;\n  };\n`;\n\nexport function unwrapEvaluateResult(payload) {\n    if (payload && typeof payload === 'object' && !Array.isArray(payload) && 'session' in payload && 'data' in payload) {\n        return payload.data;\n    }\n    return payload;\n}\n\nexport async function evaluateQoder(page, script) {\n    return unwrapEvaluateResult(await page.evaluate(script));\n}\n\nexport function requireArrayResult(value, label) {\n    if (!Array.isArray(value)) {\n        throw new CommandExecutionError(`${label}: unexpected evaluate result shape`);\n    }\n    return value;\n}\n\nexport function parsePositiveInt(raw, fallback, label) {\n    const value = raw == null || raw === '' ? fallback : Number(raw);\n    if (!Number.isInteger(value) || value < 1) {\n        throw new ArgumentError(`${label} must be a positive integer`);\n    }\n    return value;\n}\n\n// Build a JS snippet that clicks the first visible element matching any\n// of the given CSS selectors. Uses the full pointer-event chain to\n// satisfy radix/headless menu libraries.\nexport function clickFirstScript(selectors) {\n    return `(() => {\n    ${IS_VISIBLE_JS}","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/qoder/_utils.js#L22-L58","documentation":"CommandExecutionError thrown by requireArrayResult when the value unwrapped from page.evaluate() is not an array. The Qoder CLI expects injected browser scripts to resolve to arrays (items, turns) and fails loudly instead of iterating a non-array. The label names which result was malformed.","triggerScenarios":"Calling a qoder command whose evaluate script returns undefined, null, an object, or a serialized wrapper instead of an array — e.g. the page's data source changed, the script was updated to return an object, or evaluate serialization dropped the value.","commonSituations":"Target web app updated its DOM/API so the injected script returns a different shape; the evaluated script hits an error path returning undefined; page context changed after navigation; browser automation layer returning wrapped results the unwrap step doesn't recognize.","solutions":["Log the raw evaluate result to inspect the actual shape","Update the injected script to return an array (e.g. Array.from(nodeList))","Check whether the target page structure changed and revise selectors","Verify unwrapEvaluateResult handles your automation driver's result wrapper"],"exampleFix":"// before (in evaluate script)\nreturn document.querySelectorAll('.item'); // NodeList, not array\n// after\nreturn Array.from(document.querySelectorAll('.item'));","handlingStrategy":"type-guard","validationCode":"const result = await page.evaluate(script);\nif (!Array.isArray(result)) console.error('evaluate returned:', result);","typeGuard":"function isArrayOf(v, pred = () => true) { return Array.isArray(v) && v.every(pred); }","tryCatchPattern":"let items;\ntry {\n  items = requireArrayResult(await page.evaluate(script), 'items');\n} catch (e) {\n  if (/unexpected evaluate result shape/.test(e.message)) {\n    // dump raw value, revise the injected script, or retry after navigation\n  } else throw e;\n}","preventionTips":["Always return arrays from evaluate scripts (Array.from on NodeLists)","Re-check injected selectors whenever the target page updates","Log raw evaluate results during development to catch shape drift early"],"tags":["qoder","browser-automation","unexpected-shape"],"backgroundTag":"unexpected-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}