Hmbown/CodeWhale · error · ExecError
harmony uiInput text must be printable ASCII on this backend
Error message
harmony uiInput text must be printable ASCII on this backend
What it means
HarmonyOS's uiInput path can only deliver printable ASCII text; escDeviceText throws this ExecError when the string contains any character outside \x20-\x7E. This prevents silently dropping or corrupting non-ASCII characters (quotes are still escaped separately).
Solutions
- Sanitize or transliterate the string to printable ASCII before passing it (e.g. strip or replace non-ASCII characters).
- For non-ASCII content, use the clipboard backend instead: write_clipboard the text, then paste.
- Catch the ExecError and surface it to the caller rather than sending the raw string to the device.
Example fix
// before
await backend.ui_input({ text: 'café ☕' });
// after
const ascii = 'café ☕'.replace(/[^\x20-\x7E]/g, '');
if (ascii) await backend.ui_input({ text: ascii });
else await backend.write_clipboard({ text: 'café ☕' }); // then paste Defensive patterns
Strategy: try-catch
Validate before calling
if (/[^\x20-\x7E]/.test(text)) throw new TypeError('text must be printable ASCII for harmony uiInput'); Type guard
const isPrintableAscii = (s) => typeof s === 'string' && !/[^\x20-\x7E]/.test(s);
Try / catch
try { await backend.ui_input({ text }); } catch (e) { if (String(e.message).includes('printable ASCII')) { await backend.write_clipboard({ text }); await backend.perform_action(pasteAction); } else throw e; } Prevention
- Sanitize or transliterate text to ASCII before device input on HarmonyOS.
- Route non-ASCII text through the clipboard/paste path.
- Unit-test input helpers with emoji, accents, and newlines.
When it happens
Trigger: Calling uiInput / type_text with text containing Unicode letters, emoji, curly quotes, accented characters, tabs, newlines, or other control characters on the harmonyos backend.
Common situations: Typing internationalized text (CJK, Cyrillic, accents), copy-pasting smart quotes from word processors, or embedding line breaks into form fields on HarmonyOS devices.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- aa start failed
- artifact name is not portable UTF-8
- Automation name is required
- Automation prompt is required
- child stdout was not valid UTF-8
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/8266a8ce006c7a4f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/harmonyos.mjs:17
// HarmonyOS backend — drives a device/emulator through `hdc` (HarmonyOS
// Device Connector) plus the on-device `uitest` and `snapshot_display` tools.
// Observation: `uitest dumpLayout` (the accessibility-tree equivalent).
// Input: `uitest uiInput` (click / swipe / inputText / keyEvent).
// Stills: `snapshot_display`. Video: no CLI screen recorder exists on
// current HarmonyOS shells, so recording is an honest
// snapshot-series mode muxed with ffmpeg on the host.
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import crypto from "node:crypto";
import { run, runOk, ExecError, tryJson, have, currentSignal, throwIfAborted } from "../exec.mjs";
const DEVICE_TMP = "/data/local/tmp/cu";
function escDeviceText(s) {
if (/[^\x20-\x7E]/.test(s)) throw new ExecError("harmony uiInput text must be printable ASCII on this backend");
return `'${String(s).replace(/'/g, `'\\''`)}'`;
}
function jpegSize(buf) {
// Minimal JPEG SOF parser — enough to learn the panel size of a snapshot.
let i = 2;
while (i + 9 < buf.length) {
if (buf[i] !== 0xff) { i++; continue; }
const marker = buf[i + 1];
if (marker >= 0xc0 && marker <= 0xcf && ![0xc4, 0xc8, 0xcc].includes(marker)) {
return { h: buf.readUInt16BE(i + 5), w: buf.readUInt16BE(i + 7) };
}
i += 2 + buf.readUInt16BE(i + 2);
}
return null;
}
export function parseBounds(b) {View on GitHub (pinned to 73e0f67d83)