{"record":{"id":"8b377163343c835f","repo":"stablyai/orca","slug":"startup-terminal-missing","errorCode":"startup_terminal_missing","errorMessage":"startup_terminal_missing","messagePattern":"startup_terminal_missing","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/main/ipc/worktree-remote.ts","lineNumber":352,"sourceCode":"  let didSpawnSetup = false\n  if (setup) {\n    try {\n      const setupCommand =\n        wrappedSetupCommandStr ??\n        buildSetupRunnerCommand(\n          setup.runnerScriptPath,\n          getSetupRunnerCommandPlatformForLaunch(\n            setup,\n            process.platform === 'win32' ? 'windows' : 'posix'\n          ),\n          setup.shell\n        )\n      const setupLaunchMode =\n        (settings as Partial<Pick<GlobalSettings, 'setupScriptLaunchMode'>>)\n          .setupScriptLaunchMode ?? 'new-tab'\n      if (setupLaunchMode === 'split-vertical' || setupLaunchMode === 'split-horizontal') {\n        if (!startupTerminalHandle) {\n          throw new Error('startup_terminal_missing')\n        }\n        await runtime.splitTerminal(startupTerminalHandle, {\n          direction: setupLaunchMode === 'split-horizontal' ? 'horizontal' : 'vertical',\n          command: setupCommand,\n          env: setup.envVars,\n          activate: false\n        })\n      } else {\n        await runtime.createTerminal(`id:${worktree.id}`, {\n          title: 'Setup',\n          command: setupCommand,\n          env: setup.envVars,\n          activate: false\n        })\n      }\n      didSpawnSetup = true\n    } catch (error) {\n      const message = error instanceof Error ? error.message : String(error)","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/worktree-remote.ts#L334-L370","documentation":"Thrown when a worktree's setup script is configured to launch in a split pane (setupScriptLaunchMode = 'split-vertical' | 'split-horizontal') but no startup terminal handle exists to split from. The split operation needs a parent terminal; the handle is captured when the startup terminal is created. If that terminal was never created (e.g. no startup command was produced for this worktree), the handle is null and the split is impossible. The throw is a guard so splitTerminal never receives undefined.","triggerScenarios":"A create/open flow that produces a setup script but no sequenced startup terminal (startup command empty or skipped), while GlobalSettings.setupScriptLaunchMode is set to split-vertical or split-horizontal. Reached inside spawnSetupForRemoteWorktreeCreate / the launch path at worktree-remote.ts:350-353.","commonSituations":"Repo hooks define a setup script but no startup command; user switched setupScriptLaunchMode to a split mode in Settings; agent/TUI launch path that bypasses the startup terminal; a partial state where the startup terminal creation earlier returned a warning (lines 327-332) but execution continued into the setup block.","solutions":["Set setupScriptLaunchMode back to 'new-tab' in Settings so the setup script gets its own terminal instead of splitting a nonexistent one.","Ensure the repo/worktree has a real startup command so a startup terminal is created (the handle is captured at line 322).","If splitting is required, verify the startup terminal actually spawned before the setup block runs; treat a missing handle as a degraded 'new-tab' fallback rather than throwing."],"exampleFix":"// before\nif (!startupTerminalHandle) {\n  throw new Error('startup_terminal_missing')\n}\nawait runtime.splitTerminal(startupTerminalHandle, { ... })\n\n// after — degrade to a new tab when no terminal exists to split\nif (!startupTerminalHandle) {\n  await runtime.createTerminal(`id:${worktree.id}`, { title: 'Setup', command: setupCommand, env: setup.envVars, activate: false })\n} else {\n  await runtime.splitTerminal(startupTerminalHandle, { ... })\n}","handlingStrategy":"validation","validationCode":"// Before create: ensure split mode has a startup terminal to split from\nconst mode = settings.setupScriptLaunchMode ?? 'new-tab'\nconst isSplit = mode === 'split-vertical' || mode === 'split-horizontal'\nif (isSplit && !hasStartupCommandForWorktree(repo, worktree)) {\n  // downgrade instead of letting the main process throw\n  effectiveMode = 'new-tab'\n}","typeGuard":"function canSplitSetup(\n  mode: string | undefined,\n  startupTerminalHandle: string | null\n): startupTerminalHandle is string {\n  return (mode === 'split-vertical' || mode === 'split-horizontal') && startupTerminalHandle !== null\n}","tryCatchPattern":"// In the setup spawn block, treat a missing handle as degraded new-tab\ncatch (err) {\n  if (err instanceof Error && err.message === 'startup_terminal_missing') {\n    await runtime.createTerminal(`id:${worktree.id}`, { title: 'Setup', command: setupCommand, env: setup.envVars, activate: false })\n    didSpawnSetup = true\n  } else { throw err }\n}","preventionTips":["Only offer split modes in the UI when a startup command is configured for the repo.","Treat a missing startup terminal as a soft degradation (new-tab), not a hard failure.","Surface the warning captured at lines 327-332 to the user so they know the startup terminal failed."],"tags":["worktree-create","terminal","setup-script","settings"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}