{"record":{"id":"0bb81d72e6c3ea34","repo":"slopus/happy","slug":"window-identifier-required-sessionidentifier","errorCode":null,"errorMessage":"Window identifier required: ${sessionIdentifier}","messagePattern":"Window identifier required: (.+?)","errorType":"exception","errorClass":"TmuxSessionIdentifierError","httpStatus":null,"severity":"error","filePath":"packages/happy-cli/src/utils/tmux.ts","lineNumber":895,"sourceCode":"            return info;\n        } catch (error) {\n            if (error instanceof TmuxSessionIdentifierError) {\n                logger.debug(`[TMUX] Invalid session identifier: ${error.message}`);\n            } else {\n                logger.debug('[TMUX] Error getting session info:', error);\n            }\n            return null;\n        }\n    }\n\n    /**\n     * Kill a tmux window safely with proper error handling\n     */\n    async killWindow(sessionIdentifier: string): Promise<boolean> {\n        try {\n            const parsed = parseTmuxSessionIdentifier(sessionIdentifier);\n            if (!parsed.window) {\n                throw new TmuxSessionIdentifierError(`Window identifier required: ${sessionIdentifier}`);\n            }\n\n            const result = await this.executeWinOp('kill-window', [parsed.window], parsed.session);\n            return result;\n        } catch (error) {\n            if (error instanceof TmuxSessionIdentifierError) {\n                logger.debug(`[TMUX] Invalid window identifier: ${error.message}`);\n            } else {\n                logger.debug('[TMUX] Error killing window:', error);\n            }\n            return false;\n        }\n    }\n\n    /**\n     * List windows in a session\n     */\n    async listWindows(sessionName?: string): Promise<string[]> {","sourceCodeStart":877,"sourceCodeEnd":913,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/utils/tmux.ts#L877-L913","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a full 'session:window' identifier, e.g. killWindow('myproj:main').","Before calling, format the identifier with formatTmuxSessionIdentifier({ session, window }).","Log/inspect the sessionIdentifier argument at the call site to confirm the window segment exists.","If you only know the session, list its windows (list-windows) first and pick one explicitly."],"exampleFix":"// before\nawait tmux.killWindow('happy-session');\n// after\nawait tmux.killWindow('happy-session:main');","handlingStrategy":"validation","validationCode":"function canKillWindow(id) {\n  const s = String(id ?? '');\n  const colon = s.indexOf(':');\n  return colon >= 0 && s.slice(colon + 1).length > 0;\n}\nif (!canKillWindow(identifier)) throw new Error('killWindow needs session:window');","typeGuard":"function hasWindowTarget(id) {\n  return typeof id === 'string' && /^[^:]+:[^:]+$/.test(id);\n}","tryCatchPattern":"try {\n  await tmux.killWindow(id);\n} catch (e) {\n  if (e instanceof TmuxSessionIdentifierError) {\n    console.error(`Bad window target '${id}': use session:window format`);\n    return false;\n  }\n  throw e;\n}","preventionTips":["Always build identifiers with formatTmuxSessionIdentifier({ session, window }).","Never pass a bare session name to window-scoped operations.","Store session and window as separate fields and join at call time.","Unit-test identifier formatting for all call sites."],"tags":["tmux","validation","identifier-parsing"],"backgroundTag":"invalid-tmux-identifier","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}