slopus/happy · error · TmuxSessionIdentifierError

Invalid window name: "${result.window}". Only alphanumeric c

Error message

Invalid window name: "${result.window}". Only alphanumeric characters, dots, hyphens, and underscores are allowed.

What it means

When the identifier includes a window ('session:window'), parseTmuxSessionIdentifier validates the window segment against /^[a-zA-Z0-9._-]+$/ and throws this TmuxSessionIdentifierError if it contains other characters. Window names with spaces or special chars would break tmux target resolution.

Source

Thrown at packages/happy-cli/src/utils/tmux.ts:148

    if (parts.length === 0 || !parts[0]) {
        throw new TmuxSessionIdentifierError('Invalid session identifier: missing session name');
    }

    const result: TmuxSessionIdentifier = {
        session: parts[0].trim()
    };

    // Validate session name (tmux has restrictions on session names)
    if (!/^[a-zA-Z0-9._-]+$/.test(result.session)) {
        throw new TmuxSessionIdentifierError(`Invalid session name: "${result.session}". Only alphanumeric characters, dots, hyphens, and underscores are allowed.`);
    }

    if (parts.length > 1) {
        const windowAndPane = parts[1].split('.');
        result.window = windowAndPane[0]?.trim();

        if (result.window && !/^[a-zA-Z0-9._-]+$/.test(result.window)) {
            throw new TmuxSessionIdentifierError(`Invalid window name: "${result.window}". Only alphanumeric characters, dots, hyphens, and underscores are allowed.`);
        }

        if (windowAndPane.length > 1) {
            result.pane = windowAndPane[1]?.trim();
            if (result.pane && !/^[0-9]+$/.test(result.pane)) {
                throw new TmuxSessionIdentifierError(`Invalid pane identifier: "${result.pane}". Only numeric values are allowed.`);
            }
        }
    }

    return result;
}

// Helper to format tmux session identifier to string
export function formatTmuxSessionIdentifier(identifier: TmuxSessionIdentifier): string {
    if (!identifier.session) {
        throw new TmuxSessionIdentifierError('Session identifier must have a session name');
    }

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Rename the tmux window to a charset-safe name (tmux rename-window).
  2. Omit the window part and use just the session: 'happy'.
  3. Sanitize the window segment before composing the identifier string.
  4. Catch the error and re-resolve the window via tmux list-windows.

Example fix

// before
parseTmuxSessionIdentifier('happy:vim ~/notes.md'); // throws
// after
parseTmuxSessionIdentifier('happy:editor'); // renamed window
Defensive patterns

Strategy: validation

Validate before calling

const SAFE = /^[a-zA-Z0-9._-]+$/;
const [session, rest] = identifier.split(':');
const window = rest?.split('.')[0];
if (window && !SAFE.test(window)) throw new Error(`Window '${window}' must match [a-zA-Z0-9._-]+`);
parseTmuxSessionIdentifier(identifier);

Type guard

function isSafeWindowSegment(win: string | undefined): boolean {
  return win === undefined || /^[a-zA-Z0-9._-]+$/.test(win);
}

Try / catch

try {
  return parseTmuxSessionIdentifier(identifier);
} catch (err) {
  if (err instanceof TmuxSessionIdentifierError && /window name/.test(err.message)) {
    return parseTmuxSessionIdentifier(identifier.split(':')[0]); // drop window
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling parseTmuxSessionIdentifier with an identifier like 'happy:my window', 'happy:win dow.0', or a window segment interpolated from an unvalidated label.

Common situations: tmux windows auto-named after running programs (e.g. 'vim ~/notes.md') whose names contain spaces; users renaming windows freely in tmux; using a descriptive window title with punctuation.

Related errors


AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31). Data as JSON: /api/errors/1e2fe36635e29033. Report an issue: GitHub.