chenglou/pretext · error · Error

Failed to create Chrome automation tab: ${identifiers}

Error message

Failed to create Chrome automation tab: ${identifiers}

What it means

Thrown by createChromeSession after running an AppleScript that creates a new Google Chrome tab. The script is expected to return a string of the form "windowId,tabId"; the host splits on "," and Number.parseInts both halves. If either parsed value is not finite (NaN), the whole returned identifier string is surfaced in the error. This indicates the AppleScript contract with Chrome broke — the script ran but its output was not the agreed comma-pair.

Source

Thrown at scripts/browser-automation.ts:500

    'set targetWindow to front window',
    'set targetTab to make new tab at end of tabs of targetWindow with properties {URL:"about:blank"}',
  ]

  if (options.foreground === true) {
    scriptLines.splice(1, 0, 'activate')
    scriptLines.push('set active tab index of targetWindow to (count of tabs of targetWindow)')
  }

  scriptLines.push('return (id of targetWindow as string) & "," & (id of targetTab as string)')
  scriptLines.push('end tell')

  const identifiers = options.foreground === true ? runAppleScript(scriptLines) : runBackgroundAppleScript(scriptLines)

  const [windowIdRaw, tabIdRaw] = identifiers.split(',')
  const windowId = Number.parseInt(windowIdRaw ?? '', 10)
  const tabId = Number.parseInt(tabIdRaw ?? '', 10)
  if (!Number.isFinite(windowId) || !Number.isFinite(tabId)) {
    throw new Error(`Failed to create Chrome automation tab: ${identifiers}`)
  }

  return {
    navigate(url) {
      const navigateLines = [
        'tell application "Google Chrome"',
        `set targetWindow to first window whose id is ${windowId}`,
        `set URL of (first tab of targetWindow whose id is ${tabId}) to ${JSON.stringify(url)}`,
        'end tell',
      ]
      if (options.foreground === true) {
        runAppleScript(navigateLines)
      } else {
        runBackgroundAppleScript(navigateLines)
      }
    },
    readLocationUrl() {
      try {

View on GitHub (pinned to ac49b09b7d)

Solutions

  1. Run the AppleScript manually with osascript to see what `identifiers` actually contains (the error message prints it verbatim) — that string is the primary diagnostic.
  2. Confirm Google Chrome is fully launched and frontmost before invoking the session; the script makes a window only if none exist, but a half-launched Chrome returns malformed output.
  3. Open System Settings > Privacy & Security > Automation and ensure the calling terminal/IDE is allowed to control Google Chrome; re-run after toggling.
  4. Dismiss any Chrome modal dialog (update, restore pages, set-as-default) that can intercept the `make new tab` command, then retry.
  5. If the Chrome version changed the dictionary, update the scriptLines in createChromeSession to match the new `id of tab`/`id of window` shape.

Example fix

// before
const identifiers = options.foreground === true ? runAppleScript(scriptLines) : runBackgroundAppleScript(scriptLines)
const [windowIdRaw, tabIdRaw] = identifiers.split(',')
const windowId = Number.parseInt(windowIdRaw ?? '', 10)
const tabId = Number.parseInt(tabIdRaw ?? '', 10)
if (!Number.isFinite(windowId) || !Number.isFinite(tabId)) {
  throw new Error(`Failed to create Chrome automation tab: ${identifiers}`)
}
// after — surface which half failed and require exactly two parts
const parts = identifiers.split(',')
if (parts.length !== 2) {
  throw new Error(`Chrome AppleScript returned unexpected identifiers (expected "windowId,tabId"): ${JSON.stringify(identifiers)}`)
}
const windowId = Number.parseInt(parts[0] ?? '', 10)
const tabId = Number.parseInt(parts[1] ?? '', 10)
if (!Number.isFinite(windowId) || !Number.isFinite(tabId)) {
  throw new Error(`Failed to parse Chrome tab ids from ${JSON.stringify(identifiers)} (window=${windowId}, tab=${tabId})`)
}
Defensive patterns

Strategy: validation

Validate before calling

// Before createBrowserSession('chrome'), sanity-check the environment
import { execFileSync } from 'node:child_process'
function preflightChromeAppleScript(): void {
  // Chrome must be a known target the osascript dictionary recognises
  const version = execFileSync('osascript', ['-e', 'tell application "Google Chrome" to return version'], { encoding: 'utf8' }).trim()
  if (!/^\d+\./.test(version)) {
    throw new Error(`Chrome not scriptable via osascript (got: ${version})`)
  }
}
// Then: createBrowserSession('chrome', { foreground: true })

Type guard

// Narrow the AppleScript identifier contract before parsing
function isWindowTabPair(raw: string): boolean {
  const parts = raw.split(',')
  if (parts.length !== 2) return false
  return parts.every(p => Number.isFinite(Number.parseInt(p, 10)))
}
if (!isWindowTabPair(identifiers)) { /* handle gracefully */ }

Try / catch

try {
  const session = createBrowserSession('chrome', { foreground: true })
} catch (error) {
  if (error instanceof Error && error.message.startsWith('Failed to create Chrome automation tab:')) {
    // identifiers are in the message — surface to operator, do NOT silently retry the same script
    throw new Error(`Chrome automation unavailable. Check osascript permission and that Chrome is running. Detail: ${error.message}`)
  }
  throw error
}

Prevention

When it happens

Trigger: options.foreground routes to runAppleScript vs runBackgroundAppleScript; whichever returns, its trimmed stdout is split on ",". Triggers when Chrome returns an empty string, an error string, a single number, or text without a comma — e.g. Chrome is mid-launch and returned a status line, a permission dialog swallowed the real output, or a Chrome version changed the AppleScript dictionary so the `make new tab` / `id of targetTab` calls return a different shape.

Common situations: Chrome not installed or not running and AppleScript falls back to launching it cold (first-run returns unexpected output); macOS Automation permission for osascript/terminal controlling Google Chrome was denied or never granted, so osascript prints a stderr-style string to stdout; a Chrome modal (update prompt, default-browser prompt) is blocking the `make new tab`; a Chrome major-version upgrade renamed the tab-id property; running over SSH/headless where Chrome has no GUI session.

Related errors


AI-assisted analysis of chenglou/pretext@ac49b09b7d (2026-08-12). Data as JSON: /api/errors/6343d33d54169cf1. Report an issue: GitHub.