can1357/oh-my-pi · error · Error

cannot encode ctrl chord ${character}

Error message

cannot encode ctrl chord ${character}

What it means

ctrlCharacter() encodes a Ctrl-chord for the TUI debug server's key-injection protocol. Ctrl only maps cleanly for characters whose code is 64–95 (or '?', which becomes DEL); other characters have no C0 control encoding, so it throws.

Source

Thrown at packages/tui/src/debug-server.ts:115

function modifiedSpecial(sequence: string, modifier: number): string {
	if (modifier === 1) return sequence;
	if (sequence === "\t" && (modifier & 1) === 0) {
		return modifier === 2 ? "\x1b[Z" : `\x1b[1;${modifier}Z`;
	}
	const csiFinal = sequence.match(/^\x1b\[([ABCDHF])$/);
	if (csiFinal) return `\x1b[1;${modifier}${csiFinal[1]}`;
	const ss3Final = sequence.match(/^\x1bO([PQRS])$/);
	if (ss3Final) return `\x1b[1;${modifier}${ss3Final[1]}`;
	const tilde = sequence.match(/^\x1b\[(\d+)~$/);
	if (tilde) return `\x1b[${tilde[1]};${modifier}~`;
	return sequence;
}

function ctrlCharacter(character: string): string {
	const code = character.toUpperCase().charCodeAt(0);
	if ((code >= 64 && code <= 95) || code === 63) return String.fromCharCode(code === 63 ? 127 : code & 31);
	throw new Error(`cannot encode ctrl chord ${character}`);
}

function encodeChord(token: string): string {
	let rest = token;
	let ctrl = false;
	let alt = false;
	let shift = false;
	if (/^C-/i.test(rest)) {
		ctrl = true;
		rest = rest.slice(2);
	}
	if (/^(?:A|M)-/i.test(rest)) {
		alt = true;
		rest = rest.slice(2);
	}
	if (/^S-/i.test(rest)) {
		shift = true;
		rest = rest.slice(2);

View on GitHub (pinned to 9690622007)

Solutions

  1. Use a ctrl chord only with letters (a–z) or '@', '[', '\\', ']', '^', '_', '?'
  2. Remove the C- modifier from the token if the key can't be a ctrl chord
  3. Use a special key name (from SPECIAL_KEYS) with the C- prefix if supported

Example fix

// before
encodeChord("C-1") // throws
// after
encodeChord("1") // plain key, or a supported chord like "C-a"
Defensive patterns

Strategy: validation

Validate before calling

function canEncodeCtrl(ch: string): boolean {
  const code = ch.toUpperCase().charCodeAt(0);
  return (code >= 64 && code <= 95) || code === 63;
}

Type guard

function isCtrlEncodable(token: string): boolean {
  const m = /^C-(.)$/i.exec(token);
  return !m || canEncodeCtrl(m[1]);
}

Try / catch

try {
  seq = encodeChord(token);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("cannot encode ctrl chord")) {
    logger.warn("dropping non-encodable ctrl chord", { token });
    continue;
  }
  throw err;
}

Prevention

When it happens

Trigger: Encoding a key token like "C-x" where x's uppercase char code is outside 64–95 and isn't '?' — e.g. C-1, C-/, C-space-as-letter, or any digit/symbol.

Common situations: Sending debug-server key sequences with ctrl modifiers on keys that terminals themselves cannot represent as ctrl chords (digits, punctuation); typo'd key tokens in test scripts.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/c1002f55c25ec741. Report an issue: GitHub.