moeru-ai/airi · error · Error

Cannot close a DualSense controller while it is ${this.#life

Error message

Cannot close a DualSense controller while it is ${this.#lifecycle}.

What it means

close() is only valid from the 'open' lifecycle state. The guard throws when close() is called while a transition is in progress ('opening' or 'closing'), i.e. another lifecycle operation still holds the device and closing now would race with it. Calling close() while already 'closed' returns silently and never reaches this error.

Source

Thrown at packages/input-playstation-dualsense-5/src/controller.ts:99

  async close(): Promise<void> {
    if (this.#lifecycle === 'closed')
      return
    if (this.#lifecycle !== 'open')
      throw new Error(`Cannot close a DualSense controller while it is ${this.#lifecycle}.`)

    this.#lifecycle = 'closing'
    this.#device.removeEventListener('inputreport', this.#handleInputReport)
    try {
      if (this.#device.opened)
        await this.#device.close()
    }
    finally {
      this.#lifecycle = 'closed'
    }
  }

View on GitHub (pinned to 9c213115f8)

Solutions

  1. Await the in-flight open()/close() promise before calling close() — the error message names the conflicting state.
  2. Serialize lifecycle calls behind a single promise chain or mutex in the owner of the controller.
  3. If close() was triggered by teardown (page unload, component unmount), guard against duplicate teardown paths sharing one controller.
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at packages/input-playstation-dualsense-5/src/controller.ts:99 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of moeru-ai/airi@9c213115f8 (2026-09-02). Data as JSON: /api/errors/2a2cfd52325cea78. Report an issue: GitHub.