homebridge/homebridge · error · StatusResponseError

Failed to set level with on/off: ${message}

Error message

Failed to set level with on/off: ${message}

What it means

Thrown by HomebridgeLevelControlServer.moveToLevelWithOnOff when the plugin-registered handler for MoveToLevelWithOnOff throws an unexpected error. The error is wrapped in StatusResponseError with Status.Failure so the Matter endpoint remains online and the controller gets a protocol failure. The underlying message follows 'Failed to set level with on/off: '.

Source

Thrown at src/matter/behaviors/LevelControlBehavior.ts:201

      // command fails, after the plugin's handler has already run (#3993).
      // HomebridgeOnOffServer reports the coupled change to the cache instead.
      await super.moveToLevelWithOnOff(request)

      // Sync level state to cache
      registry.syncStateToCache(endpointId, 'levelControl', {
        currentLevel: request.level,
      })
    } catch (error) {
      // If user handler already threw a StatusResponseError, propagate it as-is
      // This sends a proper Matter protocol error response to the controller
      if (MatterStatus.isMatterProtocolError(error)) {
        throw error
      }

      // For other errors, wrap in appropriate StatusResponseError
      // This prevents the endpoint from crashing and keeps the device online
      const message = error instanceof Error ? error.message : String(error)
      throw new StatusResponseError(`Failed to set level with on/off: ${message}`, Status.Failure)
    }
  }
}

View on GitHub (pinned to edf5493034)

Solutions

  1. Read the text after 'Failed to set level with on/off: ' for the plugin handler's root-cause error.
  2. Fix the handler's on+level sequence: ensure power-on is awaited and both device calls are individually try/catch-wrapped.
  3. Throw StatusResponseError from the handler for domain failures to control the Matter status returned.
  4. Verify the device is online and responsive, then retry from the controller.
  5. Update the plugin or file an issue if the wrapped message reveals an internal bug.

Example fix

// before
async moveToLevelWithOnOff(level, fade) {
  await this.device.setLevel(level) // device is off, call throws
}

// after
async moveToLevelWithOnOff(level, fade) {
  if (!(await this.device.isOn())) await this.device.powerOn()
  await this.device.setLevel(level)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Plugin-side, before combined on+level:
const powered = await this.device.isOn().catch(() => false)
const clamped = Math.min(Math.max(Number(level) || 0, 1), this.maxLevel ?? 100)
if (!powered && !this.capabilities.canPowerOnWithLevel) {
  throw new StatusResponseError('Cannot set level while off', Status.Failure)
}

Type guard

const isStatusResponseError = (e: unknown): e is StatusResponseError => e instanceof StatusResponseError

Try / catch

try {
  await homeKit.setBrightness(accessoryId, level) // may include implicit power-on
} catch (e) {
  if (e instanceof StatusResponseError && e.message.startsWith('Failed to set level with on/off: ')) {
    log.error('combined on+level failed, cause: %s', e.message.slice('Failed to set level with on/off: '.length))
  }
}

Prevention

When it happens

Trigger: Controller sends MoveToLevelWithOnOff (brightness slider on an off bulb - turns it on while setting level); the plugin's registered handler throws/rejects with a non-Matter error such as a failed power-on sequence or TypeError. StatusResponseErrors from the handler pass through unwrapped.

Common situations: Handler must power the device on before setting level and the power call fails; combined on+level device API returns partial success then throws; plugin logic bug when onOff state is stale in its cache; Siri sets brightness on a switched-off light.

Related errors


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