can1357/oh-my-pi · error · TypeError

Composer style id must be a non-empty trimmed string

Error message

Composer style id must be a non-empty trimmed string

What it means

registerComposerStyle() validates extension composer style ids: the id must be non-empty after trimming and must already be trimmed. If `style.id.trim()` differs from `style.id` (leading/trailing whitespace) or trims to empty, a TypeError is thrown at registration time.

Source

Thrown at packages/tui/src/components/composer/registry.ts:46

/**
 * Whether a style paints its own row foreground.
 *
 * Extensions registered before `filledSurface` existed received undecorated
 * row text, so an omitted flag remains filled for extension-owned ids.
 */
export function isFilledComposerStyle(style: ComposerStyle): boolean {
	return style.filledSurface ?? !isBuiltinComposerStyle(style.id);
}

/**
 * Register one extension-owned composer style for this process.
 *
 * Built-in ids and duplicate extension ids are rejected. The returned disposer
 * removes only this registration.
 */
export function registerComposerStyle(style: ComposerStyle): () => void {
	const id = style.id.trim();
	if (id.length === 0 || id !== style.id) throw new TypeError("Composer style id must be a non-empty trimmed string");
	if (isBuiltinComposerStyle(id)) throw new Error(`Cannot replace built-in composer style "${id}"`);
	if (extensionComposerStyles.has(id)) throw new Error(`Composer style "${id}" is already registered`);
	extensionComposerStyles.set(id, style);
	return () => {
		if (extensionComposerStyles.get(id) === style) extensionComposerStyles.delete(id);
	};
}

/** Style object for a composer shape; unknown ids fall back to `box`. */
export function getComposerStyle(id: EditorBorderStyle): ComposerStyle {
	return extensionComposerStyles.get(id) ?? BUILTIN_COMPOSER_STYLES[id] ?? boxComposerStyle;
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Trim the id before registering: pass `id: rawId.trim()`
  2. Ensure the id is non-empty after trimming
  3. Fail fast on config parsing: validate ids at load time

Example fix

// before
registerComposerStyle({ id: name, ...style })
// after
registerComposerStyle({ id: name.trim(), ...style })
Defensive patterns

Strategy: validation

Validate before calling

function assertValidStyleId(id: string): void {
  const t = id.trim();
  if (t.length === 0 || t !== id) throw new TypeError(`invalid composer style id: ${JSON.stringify(id)}`);
}

Type guard

function isTrimmedNonEmpty(id: string): boolean {
  const t = id.trim();
  return t.length > 0 && t === id;
}

Try / catch

try {
  registerComposerStyle(style);
} catch (err) {
  if (err instanceof TypeError && err.message.includes("non-empty trimmed")) {
    style = { ...style, id: style.id.trim() || fallbackId() };
    registerComposerStyle(style);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling registerComposerStyle with a ComposerStyle whose `id` is "", " ", "my-style ", or " my-style" — any id with surrounding whitespace or empty.

Common situations: Building id strings dynamically (e.g. from user input or config) that pick up whitespace; forgetting to set an id at all; template strings that end in a newline.

Related errors


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