Hmbown/CodeWhale · critical · AggregateException

Unicode input failed: " + failure.Message + "; key-up…

Error message

Unicode input failed: " + failure.Message + "; key-up recovery failed: " + cleanup.Message

What it means

When injecting a Unicode character (KEYEVENTF_UNICODE down/up pair), the backend catches InputDeliveryException from the SendChecked of the pair. If exactly one event was inserted (only the key-down), it attempts to release that key once with a key-up; if that recovery also fails, it throws an AggregateException combining both messages, then otherwise rethrows the original failure. This prevents leaving a stuck virtual key after partial injection.

Solutions

  1. Read both inner exceptions: the original injection failure and the key-up cleanup failure, and fix the underlying cause (usually elevation/UIPI per error 284)
  2. Ensure the session stays unlocked and elevated consistently for the duration of text input
  3. Wrap text sending in try/catch and, on failure, send a harmless key (e.g. VK_SHIFT up) or reset keyboard state to clear any stuck key
  4. Retry the whole SendString after the environment stabilizes; never retry only the character that half-landed without clearing state

Example fix

// before
SendString(text);
// after
try { SendString(text); }
catch (AggregateException e) {
  // e.InnerExceptions[0] = original SendInput failure, [1] = key-up recovery failure
  ClearKeyboardState();
  throw;
}
Defensive patterns

Strategy: try-catch

Try / catch

try { SendString(text); }
catch (AggregateException e) {
  foreach (var ex in e.InnerExceptions) Log(ex.Message);
  ClearKeyboardState(); // release any stuck key
  throw;
}
catch (InputDeliveryException e) { Log(e.Message); throw; }

Prevention

When it happens

Trigger: SendString of a Unicode character when the desktop is locked/secure, UIPI blocks injection after the first event, or input is disabled mid-send — the down lands but the up does not, and the recovery up also fails.

Common situations: Text automation racing a screen lock or UAC elevation prompt; sending to an elevated app from a non-elevated process; RDP disconnecting between the pair's two events.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:63

      throw new InputDeliveryException(sent, inputs.Length, error);
    }
  }
  public static void SendKey(ushort vk, uint flags) {
    SendChecked(new INPUT[] { KeyInput(vk, 0, flags) });
  }
  public static void SendString(string text) {
    // UTF-16 code units, including both halves of surrogate pairs. UNICODE
    // requires wVk=0 and may only be combined with KEYUP, never SCANCODE.
    foreach (char c in text) {
      INPUT up = KeyInput(0, c, UNICODE | KEYUP);
      try { SendChecked(new INPUT[] { KeyInput(0, c, UNICODE), up }); }
      catch (InputDeliveryException failure) {
        // A partial pair may leave only our down event inserted. Release it
        // once, never replay text, and still report the original failure.
        if (failure.Inserted == 1) {
          try { SendChecked(new INPUT[] { up }); }
          catch (Exception cleanup) {
            throw new AggregateException("Unicode input failed: " + failure.Message + "; key-up recovery failed: " + cleanup.Message, failure, cleanup);
          }
        }
        throw;
      }
    }
  }
}`;

function recordingsDir() {
  return process.env.CODEWHALE_CU_RECORDINGS_DIR || path.join(os.homedir(), ".codewhale-cu", "recordings");
}

// Windows virtual-key codes for named keys.
const VK = {
  return: 0x0d, enter: 0x0d, tab: 0x09, escape: 0x1b, esc: 0x1b, space: 0x20,
  backspace: 0x08, delete: 0x2e, home: 0x24, end: 0x23, pageup: 0x21, pagedown: 0x22,
  left: 0x25, up: 0x26, right: 0x27, down: 0x28, capslock: 0x14, insert: 0x2d,
  f1: 0x70, f2: 0x71, f3: 0x72, f4: 0x73, f5: 0x74, f6: 0x75, f7: 0x76, f8: 0x77,

View on GitHub (pinned to 73e0f67d83)