homebridge/homebridge · error · StatusResponseError
Status.Failure
Status.Failure
Error message
Failed to change system mode: ${message} What it means
When the thermostat's systemMode attribute changes (off/heat/cool/auto), the behavior emits a `systemModeChange` event to the plugin-registered handler. If that handler throws any non-Matter error, it is wrapped as `StatusResponseError('Failed to change system mode: <message>', Status.Failure)` via the reactTo event path. The Matter attribute transaction aborts with Failure instead of crashing the endpoint.
Source
Thrown at src/matter/behaviors/ThermostatBehavior.ts:71
endpointId,
'thermostat',
'systemModeChange',
{ systemMode: value, oldSystemMode: oldValue },
)
// Sync state to cache
registry.syncStateToCache(endpointId, 'thermostat', { systemMode: value })
} 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 change system mode: ${message}`, Status.Failure)
}
}
async #handleOccupiedHeatingSetpointChanging(value: unknown): Promise<void> {
const endpointId = this.endpoint.id
const registry = this.getRegistry()
// Using 'as any' because occupiedHeatingSetpoint is feature-dependent (Heating feature)
const oldValue = (this.state as any).occupiedHeatingSetpoint
try {
// Execute user handler
await registry.executeHandler(
endpointId,
'thermostat',
'occupiedHeatingSetpointChange',
{ occupiedHeatingSetpoint: value as number, oldOccupiedHeatingSetpoint: oldValue },
)
View on GitHub (pinned to edf5493034)
Solutions
- Fix the plugin error reported after 'Failed to change system mode: '.
- Advertise only the modes the hardware supports (Thermostat cluster mode feature flags) so controllers never request unsupported modes.
- Throw StatusResponseError/InvalidCommand from the plugin for unsupported mode transitions.
- Check HVAC cloud credentials/connectivity in the plugin when the failure is intermittent.
- Serialize mode-change handling in the plugin to avoid races between controllers.
Example fix
// before
systemModeChange({ systemMode }) { return this.hvac.setMode(systemMode) } // throws on 'cool'
// after
systemModeChange({ systemMode }) {
if (!this.supportedModes.has(systemMode)) {
throw new StatusResponseError('mode not supported by hvac', Status.InvalidCommand)
}
return this.hvac.setMode(systemMode)
} Defensive patterns
Strategy: try-catch
Validate before calling
// gate mode changes on actual hardware support
const SUPPORTED_SYSTEM_MODES = new Set([0, 4, 3, 1]) // off, cool, heat, auto per device
if (!SUPPORTED_SYSTEM_MODES.has(requestedSystemMode)) {
throw new StatusResponseError('system mode not supported by hvac', Status.InvalidCommand)
}
if (!this.hvac.online) throw new StatusResponseError('hvac offline', Status.Failure) Type guard
function isMatterProtocolError(e: unknown): e is StatusResponseError {
return e instanceof StatusResponseError
|| (typeof e === 'object' && e !== null && 'status' in e && typeof (e as any).code === 'number')
} Try / catch
try {
await registry.executeHandler(endpointId, 'thermostat', 'systemModeChange', payload)
} catch (e) {
logger.warn('system mode change failed:', e instanceof Error ? e.message : e)
if (isMatterProtocolError(e)) throw e
throw new StatusResponseError(`Failed to change system mode: ${String(e)}`, Status.Failure)
} Prevention
- Advertise only system modes the HVAC hardware supports via cluster feature flags
- Keep HVAC API credentials valid; refresh tokens proactively
- Serialize mode writes to avoid races between multiple controllers
- Log the original error inside the plugin — the wrapped message is your only breadcrumb
When it happens
Trigger: A controller sets the thermostat mode in Home and the plugin's `thermostat.systemModeChange` handler rejects — e.g. the HVAC API refuses 'cool' when only heating is wired, an auth token expired, or the handler throws during a write to the physical thermostat.
Common situations: Plugins backing thermostats with partial mode support receiving a mode the hardware cannot do; cloud HVAC API downtime; mode changes made simultaneously from two controllers racing in the plugin's state.
Related errors
- Failed to stop closure: ${message}
- Failed to set color temperature: ${message}
- Failed to set hue and saturation: ${message}
- Failed to set XY color: ${message}
- Failed to set hue: ${message}
AI-assisted analysis of homebridge/homebridge@edf5493034 (2026-08-30).
Data as JSON: /api/errors/67ee7108be9d85b4.
Report an issue: GitHub.