homebridge/homebridge · error · TypeError

${pluginIdentifier} - ${platformName} attempt to unregister

Error message

${pluginIdentifier} - ${platformName} attempt to unregister an accessory that isn't PlatformAccessory!

What it means

unregisterPlatformAccessories() applies the same instanceof guard before emitting UNREGISTER_PLATFORM_ACCESSORIES, since removing a non-PlatformAccessory from the bridge would corrupt accessory state. Passing anything other than real PlatformAccessory instances throws a TypeError.

Source

Thrown at src/api.ts:813

        throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to register an accessory that isn't PlatformAccessory!`)
      }

      accessory._associatedPlugin = pluginIdentifier
      accessory._associatedPlatform = platformName
    })

    this.emit(InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, accessories)
  }

  updatePlatformAccessories(accessories: PlatformAccessory[]): void {
    this.emit(InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, accessories)
  }

  unregisterPlatformAccessories(pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]): void {
    accessories.forEach((accessory) => {
      // noinspection SuspiciousTypeOfGuard
      if (!(accessory instanceof PlatformAccessory)) {
        throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to unregister an accessory that isn't PlatformAccessory!`)
      }
    })

    this.emit(InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, accessories)
  }

  /**
   * Check if Matter is available in this version of Homebridge
   * @returns true if Homebridge version satisfies >= 2.0.0-alpha.0
   */
  isMatterAvailable(): boolean {
    return semver.gte(this.serverVersion, '2.0.0-alpha.0')
  }

  /**
   * Check if Matter is enabled for this bridge
   * For main bridge: returns true if Matter is enabled in `bridge.matter` config
   * For child bridge: returns true if Matter is enabled in the `_bridge.matter` config

View on GitHub (pinned to edf5493034)

Solutions

  1. Keep references to the actual PlatformAccessory instances you registered and pass those to unregisterPlatformAccessories.
  2. Recreate a real PlatformAccessory via `new PlatformAccessory(name, uuid)` if the original was lost, then unregister it.
  3. Deduplicate @homebridge/hap-nodejs so instanceof checks match the host's class.
  4. Verify the array does not contain undefined entries (e.g. from a failed lookup filter).

Example fix

// before
this.api.unregisterPlatformAccessories(pluginName, platformName, this.cache.map(a => JSON.parse(a)));
// after
const toRemove = this.cache.map(a => this.accessories.get(a.uuid)!).filter(a => a instanceof PlatformAccessory);
this.api.unregisterPlatformAccessories(pluginName, platformName, toRemove);
Defensive patterns

Strategy: type-guard

Validate before calling

const valid = accessories.filter(a => a instanceof PlatformAccessory);
if (valid.length !== accessories.length) {
  log.warn('Skipping non-PlatformAccessory items in unregister call');
}

Type guard

function isPlatformAccessory(a: unknown): a is PlatformAccessory {
  return a instanceof PlatformAccessory;
}

Try / catch

try {
  api.unregisterPlatformAccessories(plugin, platformName, accessories);
} catch (e) {
  if (e instanceof TypeError && e.message.includes('unregister')) {
    log.error('Only unregister accessories originally obtained from registration events');
  }
}

Prevention

When it happens

Trigger: Calling api.unregisterPlatformAccessories(pluginIdentifier, platformName, accessories) with plain objects, stale/foreign accessory copies, or items reconstructed from persisted JSON instead of the actual accessory objects returned by the `didRegisterPlatformAccessories` event or kept by the plugin.

Common situations: Dynamic platforms removing accessories after holding them in a custom cache that was serialized/deserialized; plugin reloads losing the original instances; duplicate hap-nodejs copies making instanceof fail.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of homebridge/homebridge@edf5493034 (2026-08-30). Data as JSON: /api/errors/aa78c8cad4cf43c9. Report an issue: GitHub.