Hmbown/CodeWhale · error · ExecError

harmony backend exposes display 1 only

Error message

harmony backend exposes display 1 only

What it means

switch_display on the HarmonyOS backend fails because the backend only exposes display 1: displays are enumerated from a snapshot_display probe and hdc offers a single display surface, so any other requested display index is rejected.

Solutions

  1. Pass index: 1, the only display this backend exposes.
  2. Skip switch_display entirely — the single device display is already active.
  3. Gate display-switching logic on backend type or on list_displays() results.

Example fix

// before
await backend.switch_display({ index: 0 });
// after
const displays = await backend.list_displays();
if (displays.length > 1) await backend.switch_display({ index: displays[0].index }); // index 1 on harmonyos
Defensive patterns

Strategy: validation

Validate before calling

if (index !== 1) throw new TypeError('harmony backend exposes display 1 only');

Type guard

const isHarmonyDisplay = (i) => i === 1;

Try / catch

try { await backend.switch_display({ index }); } catch (e) { if (String(e.message).includes('display 1 only')) { /* single-display device; stay on display 1 */ } else throw e; }

Prevention

When it happens

Trigger: Calling switch_display({index: 0}) or any index other than 1 on the harmonyos backend.

Common situations: Code written for multi-display macOS backends using 0-based display indexes; enumerating displays generically and switching to the 'first' one (index 0); ported automation scripts assuming multiple monitors.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/6cc0226efef896d2. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/backends/harmonyos.mjs:168

        connected,
        targets,
        capabilities: { screenshot: connected, accessibility_tree: connected, clipboard: false, recording: "snapshot-series" },
        note: "HarmonyOS drives the device over hdc. Clipboard read/write is not exposed by hdc and fails closed. Recording muxes snapshot_display frames with ffmpeg.",
      };
    },
    list_displays: async () => {
      if (!displayPixels) {
        const dir = fs.mkdtempSync(path.join(os.tmpdir(), "cu-hm-"));
        try {
          const shot = path.join(dir, "probe.jpeg");
          await snapshot(shot);
          displayPixels = jpegSize(fs.readFileSync(shot)) ?? { w: null, h: null };
        } finally { fs.rmSync(dir, { recursive: true, force: true }).catch(() => {}); }
      }
      return [{ index: 1, name: "device", pixels: displayPixels, points: displayPixels, scale: 1, main: true }];
    },
    async switch_display({ index }) {
      if (index !== 1) throw new ExecError("harmony backend exposes display 1 only");
      return { activeDisplay: 1 };
    },
    list_apps: async () => {
      const out = await deviceOut(["bm", "dump", "-a"], { timeoutMs: 25_000 });
      const bundles = out.split("\n").map((s) => s.trim()).filter((s) => /^[a-zA-Z][\w.]*$/.test(s));
      return { apps: bundles.map((b) => ({ name: b, bundle_id: b, kind: "bundle" })) };
    },
    list_windows: async (args = {}) => {
      rejectAppSelectors(args);
      const out = await deviceOut(["hidumper", "-s", "WindowManagerService", "-a", "-a"], { timeoutMs: 25_000 }).catch(() => "");
      const windows = out.split("\n").filter((l) => /Window Name|bundleName/i.test(l)).slice(0, 40).map((l) => ({ title: l.trim().slice(0, 160) }));
      return { windows: windows.length ? windows : [{ title: "(window list unavailable on this HarmonyOS build)" }] };
    },
    open_application: async ({ bundle_id: bid, ability, name } = {}) => {
      const bundle = bid ?? name;
      const identifier = (value) => typeof value === "string" && value.length <= 256 && /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(value);
      if (!identifier(bundle)) throw new ExecError("open_application needs a valid Harmony bundle identifier");
      if (ability != null && !identifier(ability)) throw new ExecError("open_application needs a valid Harmony ability identifier");

View on GitHub (pinned to 73e0f67d83)