{"record":{"id":"877b8b1ceee5b1b5","repo":"slopus/happy","slug":"invalid-session-identifier-missing-session-name","errorCode":null,"errorMessage":"Invalid session identifier: missing session name","messagePattern":"Invalid session identifier: missing session name","errorType":"exception","errorClass":"TmuxSessionIdentifierError","httpStatus":null,"severity":"error","filePath":"packages/happy-cli/src/utils/tmux.ts","lineNumber":131,"sourceCode":"\n/** Validation error for tmux session identifiers */\nexport class TmuxSessionIdentifierError extends Error {\n    constructor(message: string) {\n        super(message);\n        this.name = 'TmuxSessionIdentifierError';\n    }\n}\n\n// Helper to parse tmux session identifier from string with validation\nexport function parseTmuxSessionIdentifier(identifier: string): TmuxSessionIdentifier {\n    if (!identifier || typeof identifier !== 'string') {\n        throw new TmuxSessionIdentifierError('Session identifier must be a non-empty string');\n    }\n\n    // Format: session:window or session:window.pane or just session\n    const parts = identifier.split(':');\n    if (parts.length === 0 || !parts[0]) {\n        throw new TmuxSessionIdentifierError('Invalid session identifier: missing session name');\n    }\n\n    const result: TmuxSessionIdentifier = {\n        session: parts[0].trim()\n    };\n\n    // Validate session name (tmux has restrictions on session names)\n    if (!/^[a-zA-Z0-9._-]+$/.test(result.session)) {\n        throw new TmuxSessionIdentifierError(`Invalid session name: \"${result.session}\". Only alphanumeric characters, dots, hyphens, and underscores are allowed.`);\n    }\n\n    if (parts.length > 1) {\n        const windowAndPane = parts[1].split('.');\n        result.window = windowAndPane[0]?.trim();\n\n        if (result.window && !/^[a-zA-Z0-9._-]+$/.test(result.window)) {\n            throw new TmuxSessionIdentifierError(`Invalid window name: \"${result.window}\". Only alphanumeric characters, dots, hyphens, and underscores are allowed.`);\n        }","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/utils/tmux.ts#L113-L149","documentation":"After splitting the identifier on ':', parseTmuxSessionIdentifier requires the first segment (the tmux session name) to be non-empty. An identifier like ':0.0' or ':window' has no session part, which tmux cannot resolve, so this TmuxSessionIdentifierError is thrown.","triggerScenarios":"Calling parseTmuxSessionIdentifier with a string whose pre-colon segment is empty or whitespace, e.g. ':0.0', ':main', or a template like `${missingVar}:0` where the variable is empty.","commonSituations":"String interpolation of an unset session variable into an identifier; manually copying a target string from tmux output but dropping the session prefix; storing only the window part and prefixing ':' by mistake.","solutions":["Include the session name before the colon: 'happy:0.0' instead of ':0.0'.","Fix the interpolation source so the session variable is populated.","If only a window is known, use formatTmuxSessionIdentifier with an explicit session field.","Pre-validate with a regex like /^[^:]+/ before parsing."],"exampleFix":"// before\nparseTmuxSessionIdentifier(':0.0'); // throws\n// after\nparseTmuxSessionIdentifier('happy:0.0');","handlingStrategy":"validation","validationCode":"const m = /^[^:]+/.exec(identifier);\nif (!m || !m[0].trim()) throw new Error('identifier must start with a session name');\nparseTmuxSessionIdentifier(identifier);","typeGuard":"function hasSessionName(id: string): boolean {\n  return /^[^:]+/.test(id);\n}","tryCatchPattern":"try {\n  return parseTmuxSessionIdentifier(identifier);\n} catch (err) {\n  if (err instanceof TmuxSessionIdentifierError) {\n    throw new Error(`Bad tmux target '${identifier}': use 'session[:window[.pane]]'`);\n  }\n  throw err;\n}","preventionTips":["Always build identifiers as `${session}:${window}.${pane}` from named variables, not manual string edits.","Guard interpolations so an undefined session can't collapse the prefix.","Validate user-supplied targets with a regex before parsing."],"tags":["tmux","validation","input-validation"],"backgroundTag":"invalid-tmux-session-identifier","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}