slopus/happy · error · TmuxSessionIdentifierError

Window identifier required: ${sessionIdentifier}

Error message

Window identifier required: ${sessionIdentifier}

What it means

killWindow() kills a tmux window but requires an identifier that names BOTH a session and a window (e.g. 'session:window'). parseTmuxSessionIdentifier() splits the string; if no window component is present (e.g. just a session name), this TmuxSessionIdentifierError is thrown instead of running a dangerous or ambiguous 'kill-window' tmux command.

Source

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

            return info;
        } catch (error) {
            if (error instanceof TmuxSessionIdentifierError) {
                logger.debug(`[TMUX] Invalid session identifier: ${error.message}`);
            } else {
                logger.debug('[TMUX] Error getting session info:', error);
            }
            return null;
        }
    }

    /**
     * Kill a tmux window safely with proper error handling
     */
    async killWindow(sessionIdentifier: string): Promise<boolean> {
        try {
            const parsed = parseTmuxSessionIdentifier(sessionIdentifier);
            if (!parsed.window) {
                throw new TmuxSessionIdentifierError(`Window identifier required: ${sessionIdentifier}`);
            }

            const result = await this.executeWinOp('kill-window', [parsed.window], parsed.session);
            return result;
        } catch (error) {
            if (error instanceof TmuxSessionIdentifierError) {
                logger.debug(`[TMUX] Invalid window identifier: ${error.message}`);
            } else {
                logger.debug('[TMUX] Error killing window:', error);
            }
            return false;
        }
    }

    /**
     * List windows in a session
     */
    async listWindows(sessionName?: string): Promise<string[]> {

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Pass a full 'session:window' identifier, e.g. killWindow('myproj:main').
  2. Before calling, format the identifier with formatTmuxSessionIdentifier({ session, window }).
  3. Log/inspect the sessionIdentifier argument at the call site to confirm the window segment exists.
  4. If you only know the session, list its windows (list-windows) first and pick one explicitly.

Example fix

// before
await tmux.killWindow('happy-session');
// after
await tmux.killWindow('happy-session:main');
Defensive patterns

Strategy: validation

Validate before calling

function canKillWindow(id) {
  const s = String(id ?? '');
  const colon = s.indexOf(':');
  return colon >= 0 && s.slice(colon + 1).length > 0;
}
if (!canKillWindow(identifier)) throw new Error('killWindow needs session:window');

Type guard

function hasWindowTarget(id) {
  return typeof id === 'string' && /^[^:]+:[^:]+$/.test(id);
}

Try / catch

try {
  await tmux.killWindow(id);
} catch (e) {
  if (e instanceof TmuxSessionIdentifierError) {
    console.error(`Bad window target '${id}': use session:window format`);
    return false;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling killWindow() with a bare session name like 'happy-abc123', an empty string, or a 'session:' value with an empty window part — anything parseTmuxSessionIdentifier returns without a window field.

Common situations: Passing a tmux session identifier (not a window identifier) from config or a stored session string; upstream code refactored from session-scoped to window-scoped targeting; a window name was dropped when formatting the identifier.

Related errors


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