slopus/happy · error · TmuxSessionIdentifierError

Session identifier must have a session name

Error message

Session identifier must have a session name

What it means

formatTmuxSessionIdentifier converts a TmuxSessionIdentifier object back into a 'session:window.pane' string and requires the session field to be a non-empty string. If identifier.session is missing, null, or empty, it throws this TmuxSessionIdentifierError because the resulting target string would be invalid.

Source

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

        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');
    }

    let result = identifier.session;
    if (identifier.window) {
        result += `:${identifier.window}`;
        if (identifier.pane) {
            result += `.${identifier.pane}`;
        }
    }
    return result;
}

// Helper to extract session and window from tmux output with improved validation
export function extractSessionAndWindow(tmuxOutput: string): { session: string; window: string } | null {
    if (!tmuxOutput || typeof tmuxOutput !== 'string') {
        return null;
    }

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Always set session before formatting: { session: 'happy', window: '0' }.
  2. Apply a default when the source value is empty: session ?? 'happy'.
  3. Check the object with a type guard before calling format.
  4. Catch TmuxSessionIdentifierError and re-create the identifier from defaults.

Example fix

// before
formatTmuxSessionIdentifier({ window: '0' }); // throws
// after
formatTmuxSessionIdentifier({ session: activeSession ?? 'happy', window: '0' });
Defensive patterns

Strategy: type-guard

Validate before calling

function canFormatTmuxIdentifier(id: TmuxSessionIdentifier): boolean {
  return typeof id.session === 'string' && id.session.length > 0;
}
if (!canFormatTmuxIdentifier(id)) throw new Error('session required before formatting');
formatTmuxSessionIdentifier(id);

Type guard

function hasSession(id: TmuxSessionIdentifier): id is TmuxSessionIdentifier & { session: string } {
  return typeof id.session === 'string' && id.session.length > 0;
}

Try / catch

try {
  return formatTmuxSessionIdentifier(id);
} catch (err) {
  if (err instanceof TmuxSessionIdentifierError) {
    return formatTmuxSessionIdentifier({ ...id, session: id.session || 'happy' });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling formatTmuxSessionIdentifier({} ), { session: '' }, { window: '0' } — building the object dynamically where the session field was never assigned, or spreading a partial object returned by an earlier failed parse.

Common situations: Constructing the identifier from optional config fields where session defaulted to undefined; persisting/restoring a serialized identifier that lost its session key; programmatically building targets from list output that lacked a session name.

Related errors


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