{"record":{"id":"ca9b01a173d8058e","repo":"jackwener/OpenCLI","slug":"geogebra-command-returned-malformed-result","errorCode":null,"errorMessage":"GeoGebra command returned malformed result","messagePattern":"GeoGebra command returned malformed result","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/geogebra/utils.js","lineNumber":157,"sourceCode":"        const label = ggbApplet.evalCommandGetLabels(cmd);\n        const afterCount = collectNames().length;\n        const dialogText = [...document.querySelectorAll('[role=\"dialog\"], .gwt-DialogBox')]\n          .map(node => node.textContent?.trim() || '')\n          .find(text => /error|unknown command|错误|未知的指令/i.test(text)) || '';\n        return {\n          ok: label !== '' || afterCount > beforeCount,\n          label,\n          beforeCount,\n          afterCount,\n          error: dialogText || null,\n        };\n      })(${JSON.stringify(cmd)})\n    `));\n  } catch (err) {\n    throw new CommandExecutionError(`Failed to execute GeoGebra command: ${err?.message || err}`);\n  }\n  if (!isPlainObject(result) || typeof result.ok !== 'boolean') {\n    throw new CommandExecutionError('GeoGebra command returned malformed result');\n  }\n  return result;\n}\n\n/**\n * List all currently known GeoGebra objects, optionally filtered by type.\n */\nexport async function ggbListObjects(page, filterType) {\n  const normalizedFilter = filterType ? String(filterType).toLowerCase() : '';\n  let objects;\n  try {\n    objects = unwrapBridgeEnvelope(await page.evaluate(`\n      (filterType => {\n        const api = ggbApplet;\n        let names = api.getAllObjectNames();\n        if (typeof names === 'string') {\n          names = names.split(',').map(s => s.trim()).filter(Boolean);\n        }","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/geogebra/utils.js#L139-L175","documentation":"ggbEval() checks that the value returned from page.evaluate is a plain object with a boolean ok field before returning it. If the bridge returns anything else (undefined, null, string, object missing ok), it throws CommandExecutionError 'GeoGebra command returned malformed result', protecting downstream requireGgbSuccess consumers from undefined-shaped access.","triggerScenarios":"The in-page helper returns early with a non-object (e.g. an unwrapped primitive or an error path returning undefined), unwrapBridgeEnvelope mangles the envelope, or a browser serialization issue drops the object so evaluate resolves to undefined.","commonSituations":"GeoGebra page updated so the injected helper's return shape changed, custom bridge/shim layers altering the envelope, evaluate() hitting the wrong frame (applet iframe vs top document), or structured-clone issues with exotic return values.","solutions":["Log the raw evaluate return to see the actual shape, and confirm the injected helper always returns { ok: boolean, ... } on every path.","Verify page.evaluate targets the correct frame/context where ggbApplet lives.","Update unwrapBridgeEnvelope if the bridge protocol changed after a GeoGebra site update.","Catch this CommandExecutionError and retry after re-running ensureApplet, since a mid-update page can transiently return undefined."],"exampleFix":"// before\nconst r = await page.evaluate(\"ggbApplet.evalCommandGetLabels(cmd)\"); // may be boolean/undefined\n// after\nconst r = await page.evaluate(\"(() => { try { return { ok: true, value: ggbApplet.evalCommandGetLabels(cmd) }; } catch (e) { return { ok: false, error: String(e) }; } })()\");","handlingStrategy":"type-guard","validationCode":"if (!result || typeof result.ok !== 'boolean') { await ensureApplet(page); result = await ggbEval(page, cmd); }","typeGuard":"const isEvalResult = (v) => typeof v === 'object' && v !== null && typeof v.ok === 'boolean';","tryCatchPattern":"try { const r = await ggbEval(page, cmd); if (!isEvalResult(r)) throw new Error('unexpected bridge shape'); } catch (e) { /* re-ensure applet, log raw return, retry */ }","preventionTips":["Pin/test against GeoGebra page updates that change bridge return shapes.","Always return a structured { ok, ... } object from injected helpers, even on error paths.","Target the correct frame where ggbApplet is defined.","Log raw evaluate output when a shape mismatch is suspected."],"tags":["automation","browser","result-parsing","geogebra"],"backgroundTag":"malformed-response-envelope","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}