jackwener/OpenCLI · error · CommandExecutionError

GeoGebra command returned malformed result

Error message

GeoGebra command returned malformed result

What it means

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.

Source

Thrown at clis/geogebra/utils.js:157

        const label = ggbApplet.evalCommandGetLabels(cmd);
        const afterCount = collectNames().length;
        const dialogText = [...document.querySelectorAll('[role="dialog"], .gwt-DialogBox')]
          .map(node => node.textContent?.trim() || '')
          .find(text => /error|unknown command|错误|未知的指令/i.test(text)) || '';
        return {
          ok: label !== '' || afterCount > beforeCount,
          label,
          beforeCount,
          afterCount,
          error: dialogText || null,
        };
      })(${JSON.stringify(cmd)})
    `));
  } catch (err) {
    throw new CommandExecutionError(`Failed to execute GeoGebra command: ${err?.message || err}`);
  }
  if (!isPlainObject(result) || typeof result.ok !== 'boolean') {
    throw new CommandExecutionError('GeoGebra command returned malformed result');
  }
  return result;
}

/**
 * List all currently known GeoGebra objects, optionally filtered by type.
 */
export async function ggbListObjects(page, filterType) {
  const normalizedFilter = filterType ? String(filterType).toLowerCase() : '';
  let objects;
  try {
    objects = unwrapBridgeEnvelope(await page.evaluate(`
      (filterType => {
        const api = ggbApplet;
        let names = api.getAllObjectNames();
        if (typeof names === 'string') {
          names = names.split(',').map(s => s.trim()).filter(Boolean);
        }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the raw evaluate return to see the actual shape, and confirm the injected helper always returns { ok: boolean, ... } on every path.
  2. Verify page.evaluate targets the correct frame/context where ggbApplet lives.
  3. Update unwrapBridgeEnvelope if the bridge protocol changed after a GeoGebra site update.
  4. Catch this CommandExecutionError and retry after re-running ensureApplet, since a mid-update page can transiently return undefined.

Example fix

// before
const r = await page.evaluate("ggbApplet.evalCommandGetLabels(cmd)"); // may be boolean/undefined
// after
const r = await page.evaluate("(() => { try { return { ok: true, value: ggbApplet.evalCommandGetLabels(cmd) }; } catch (e) { return { ok: false, error: String(e) }; } })()");
Defensive patterns

Strategy: type-guard

Validate before calling

if (!result || typeof result.ok !== 'boolean') { await ensureApplet(page); result = await ggbEval(page, cmd); }

Type guard

const isEvalResult = (v) => typeof v === 'object' && v !== null && typeof v.ok === 'boolean';

Try / catch

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 */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/ca9b01a173d8058e. Report an issue: GitHub.