{"record":{"id":"57d9b0dbe0a98032","repo":"jackwener/OpenCLI","slug":"bound-window-operation-blocked","errorCode":"bound_window_operation_blocked","errorMessage":"Session \"${existing.session}\" is bound to a user tab and does not own an OpenCLI tab lease.","messagePattern":"Session \"(.+?)\" is bound to a user tab and does not own an OpenCLI tab lease\\.","errorType":"error_code","errorClass":"CommandFailure","httpStatus":null,"severity":"error","filePath":"extension/src/background.ts","lineNumber":1129,"sourceCode":"    kind: 'owned',\n    windowId: sessionWindowId,\n    owned: true,\n    preferredTabId: tabId,\n  });\n  resetWindowIdleTimer(leaseKey);\n  return { tabId, tab };\n}\n\n/** Get or create the dedicated automation container window.\n *  This compatibility helper returns the shared owned container. Leases\n *  lease tabs inside it instead of owning separate windows.\n */\nasync function getAutomationWindow(leaseKey: string, initialUrl?: string): Promise<number> {\n  // Check if our window is still alive.\n  const existing = automationSessions.get(leaseKey);\n  if (existing) {\n    if (!existing.owned) {\n      throw new CommandFailure(\n        'bound_window_operation_blocked',\n        `Session \"${existing.session}\" is bound to a user tab and does not own an OpenCLI tab lease.`,\n        'Use page commands on the bound tab, or unbind the session first.',\n      );\n    }\n    try {\n      const tabId = existing.preferredTabId;\n      if (tabId !== null) {\n        const tab = await chrome.tabs.get(tabId);\n        if (isDebuggableUrl(tab.url)) return tab.windowId;\n      }\n      await chrome.windows.get(existing.windowId);\n      return existing.windowId;\n    } catch {\n      // Tab/window was closed by user\n      await removeLeaseSession(leaseKey);\n    }\n  }","sourceCodeStart":1111,"sourceCodeEnd":1147,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/extension/src/background.ts#L1111-L1147","documentation":"getAutomationWindow looks up the lease's automation session; if the session exists but is only bound to a user tab (existing.owned === false), the session does not own an OpenCLI-managed window/tab group, so window-level operations are refused with CommandFailure code 'bound_window_operation_blocked'. The library distinguishes owned automation windows from user-bound tabs and only allows window operations on the former.","triggerScenarios":"Running a window-level automation command (resize, focus, snapshot, etc.) against a session that was previously bound to a regular user tab rather than created as an owned automation window — getAutomationWindow detects existing && !existing.owned and throws.","commonSituations":"Attaching the automation session to a manually opened browser tab, then trying window commands on it; a lease got downgraded from owned to bound after its group/window was dissolved; scripts assuming every session owns a window.","solutions":["Use page-level commands on the bound tab instead of window-level commands","Unbind the session (unbind command) and re-open it as an owned automation window","Create a new named session via the normal open flow so it owns its own window/tab group"],"exampleFix":"// before\nawait runCommand('mysession', 'window resize', { width: 1280 });\n// after\nconst mode = await getSessionMode('mysession'); // 'owned' | 'bound'\nif (mode === 'bound') await runCommand('mysession', 'unbind');\nawait runCommand('mysession', 'window resize', { width: 1280 });","handlingStrategy":"try-catch","validationCode":"// before window-level commands, check ownership\nconst owned = await isOwnedAutomationSession(sessionName); // e.g. via status command\nif (!owned) console.warn('Session is bound to a user tab; window commands will be blocked');","typeGuard":null,"tryCatchPattern":"try {\n  await windowCommand(session);\n} catch (e) {\n  if (e.code === 'bound_window_operation_blocked') {\n    console.error('Use page commands on the bound tab, or unbind and reopen as an owned session');\n  } else throw e;\n}","preventionTips":["Only issue window-level commands to sessions created through the owned open flow","Check session status (owned vs bound) before window operations","After a group/window is dissolved, re-open the session rather than reusing a bound lease"],"tags":["chrome-extension","session","window","permission"],"backgroundTag":"session-not-owned-window-operation-blocked","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}