SeleniumHQ/selenium · error · TypeError

browsingContexts should be string or string array

Error message

browsingContexts should be string or string array

What it means

Thrown by BiDi session.subscribe() when the browsingContexts argument is neither a string nor an array of strings. After normalizing the argument through toArray(), the client validates that each context identifier is a string, because the session.subscribe command requires context IDs as strings. A non-string element would serialize to an invalid command payload, so it is rejected client-side first.

Source

Thrown at javascript/selenium-webdriver/bidi/index.js:259

      }

      return Array.isArray(arg) ? [...arg] : [arg]
    }

    const eventsArray = toArray(events)
    const contextsArray = toArray(browsingContexts)

    const params = {
      method: 'session.subscribe',
      params: {},
    }

    if (eventsArray.length && eventsArray.some((event) => typeof event !== 'string')) {
      throw new TypeError('events should be string or string array')
    }

    if (contextsArray.length && contextsArray.some((context) => typeof context !== 'string')) {
      throw new TypeError('browsingContexts should be string or string array')
    }

    if (eventsArray.length) {
      params.params.events = eventsArray
    }

    if (contextsArray.length) {
      params.params.contexts = contextsArray
    }

    this.events.push(...eventsArray)

    await this.send(params)
  }

  /**
   * Unsubscribe to events
   * @param events

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Pass context identifiers as a string or an array of strings (e.g. subscribe('log.entryAdded', 'ctx12345') or subscribe('log.entryAdded', ['ctx12345','ctx67890'])).
  2. If you hold context objects, extract the id string first (e.g. info.context) before calling subscribe.
  3. Omit the browsingContexts argument entirely to subscribe globally, which avoids the check because undefined becomes an empty array.

Example fix

// before
const info = await browsingContext.create(contextDescriptor)
await bidi.subscribe('log.entryAdded', info) // info is an object

// after
await bidi.subscribe('log.entryAdded', info.context) // pass the id string
Defensive patterns

Strategy: validation

Validate before calling

function assertStringContexts(contexts) {
  const arr = Array.isArray(contexts) ? contexts : contexts === undefined ? [] : [contexts]
  if (arr.length && arr.some((c) => typeof c !== 'string')) {
    throw new TypeError('browsingContexts must be string or string[]')
  }
  return arr
}

Type guard

function isContextIdList(v) {
  if (v === undefined) return true
  if (typeof v === 'string') return true
  return Array.isArray(v) && v.every((c) => typeof c === 'string')
}

Try / catch

try {
  await bidi.subscribe(events, contexts)
} catch (e) {
  if (e instanceof TypeError && /browsingContexts should be string/i.test(e.message)) {
    // extract id strings from context objects and retry
  } else throw e
}

Prevention

When it happens

Trigger: Calling bidi.subscribe(events, browsingContexts) where browsingContexts is a number, object, null, or an array containing non-string elements (e.g. subscribe('log.entryAdded', window), subscribe('log.entryAdded', [123]), or subscribe('log.entryAdded', [{context:'abc'}])).

Common situations: Passing a context object or wrapper instead of its string id; reusing a variable typed as a number/BigInt context handle; forgetting to extract the .context field from a BrowsingContextInfo object before subscribing.

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/31bd52616af2c1e3. Report an issue: GitHub.