{"record":{"id":"fe889273b078d76d","repo":"jackwener/OpenCLI","slug":"message-malformed-geogebra-result","errorCode":null,"errorMessage":"${message}: malformed GeoGebra result","messagePattern":"(.+?): malformed GeoGebra result","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/geogebra/utils.js","lineNumber":60,"sourceCode":"  const raw = value == null || value === '' ? defaultValue : value;\n  const number = Number(raw);\n  if (!Number.isFinite(number) || (positive && number <= 0)) {\n    throw new ArgumentError(`${label} must be a ${positive ? 'positive ' : ''}finite number`);\n  }\n  return number;\n}\n\nexport function normalizeCoords(value) {\n  const parts = String(value ?? '').split(',').map(s => s.trim());\n  if (parts.length !== 2) {\n    throw new ArgumentError('coords must be in \"x,y\" format (e.g. \"1,2\")');\n  }\n  return parts.map((part, idx) => normalizeNumber(part, idx === 0 ? 'x' : 'y'));\n}\n\nexport function requireGgbSuccess(result, message) {\n  if (!isPlainObject(result)) {\n    throw new CommandExecutionError(`${message}: malformed GeoGebra result`);\n  }\n  if (!result.ok) {\n    throw new CommandExecutionError(result.error || message);\n  }\n  return result;\n}\n\n/**\n * Navigate to GeoGebra Geometry (if not already there) and wait for\n * the ggbApplet API to become available.\n */\nexport async function ensureApplet(page) {\n  let currentUrl = '';\n  try {\n    currentUrl = await page.getCurrentUrl();\n  } catch {\n    currentUrl = '';\n  }","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/geogebra/utils.js#L42-L78","documentation":"requireGgbSuccess() validates the object returned by the GeoGebra bridge (via ggbEval) before inspecting it. It throws CommandExecutionError when the result is not a plain object, meaning the browser bridge returned something unexpected (null, a string, undefined) rather than the expected { ok, ... } envelope.","triggerScenarios":"The page.evaluate call unwraps to a non-object (bridge/envelope mangled the return), the GeoGebra page was replaced mid-command, or a proxy/extension stripped the structured result so requireGgbSuccess receives null/undefined/string.","commonSituations":"Browser automation sessions where the applet iframe reloaded during a command, stale page handles after navigation, or a modified/misbehaving unwrapBridgeEnvelope layer returning raw values.","solutions":["Check that the GeoGebra page is still loaded and the applet exists (re-run ensureApplet) before retrying the command.","Verify unwrapBridgeEnvelope handles the bridge's actual envelope format; log the raw return value from page.evaluate to see what was received.","Re-navigate to the GeoGebra Geometry page and retry the command once the applet reports ready.","Catch CommandExecutionError around the tool call and treat it as a transient automation failure."],"exampleFix":"// before\nconst result = await ggbEval(page, 'A=(1,2)');\nrequireGgbSuccess(result, 'Create point');\n// after\nlet result = await ggbEval(page, 'A=(1,2)');\nif (!isPlainObject(result)) { await ensureApplet(page); result = await ggbEval(page, 'A=(1,2)'); }\nrequireGgbSuccess(result, 'Create point');","handlingStrategy":"type-guard","validationCode":"if (result == null || typeof result !== 'object' || Array.isArray(result)) { await ensureApplet(page); result = await ggbEval(page, cmd); }","typeGuard":"const isPlainObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try { requireGgbSuccess(result, 'Create point'); } catch (e) { if (String(e.message).includes('malformed')) { await ensureApplet(page); /* retry once */ } else throw e; }","preventionTips":["Re-run ensureApplet after any navigation or page replacement.","Never share page handles across navigation boundaries without re-validating.","Log raw evaluate output when debugging bridge format changes."],"tags":["automation","browser","result-parsing"],"backgroundTag":"malformed-response-envelope","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}