Appearance
Troubleshooting
Common errors encountered when developing HOS drivers, with causes and solutions.
All error responses from the server follow this envelope:
json
{
"ok": false,
"code": "DRIVER_WS_VALIDATION_ERROR",
"error": "Human-readable error message",
"details": ["Specific detail 1", "Specific detail 2"],
"protocolVersion": 1
}Registration Errors
Registration errors occur during the driver.register handshake. See Driver Lifecycle for the full registration flow.
Missing protocolVersion
Error: "protocolVersion is required for driver.register."
Detail: "Set protocolVersion: 1."
Cause: The driver.register message did not include protocolVersion.
Solution: The HOS SDK sets this automatically. If calling register manually, include protocolVersion: 1 in the params:
typescript
// Manual register message (not needed when using HosDriver)
{
method: 'driver.register',
params: {
driverKey: 'MY_DRIVER',
instanceId: 'my-driver:001',
protocolVersion: 1, // required
}
}Invalid driverKey
Error: "Invalid driver.register payload."
Detail: "driverKey must match [A-Z0-9_] and be 2-64 chars."
Cause: The driverKey contains invalid characters or is too short/long.
Solution: Use only uppercase letters, digits, and underscores. The SDK auto-uppercases the key, but it must still be 2-64 characters.
typescript
// Correct
new HosDriver({ driverKey: 'MY_DRIVER', ... })
new HosDriver({ driverKey: 'HUE_BRIDGE', ... })
// Invalid — contains hyphen and lowercase
new HosDriver({ driverKey: 'my-driver!', ... })Invalid instanceId
Error: "Invalid driver.register payload."
Detail: "instanceId must match [a-zA-Z0-9:_-] and be 1-128 chars."
Cause: The instanceId contains invalid characters or is empty/too long.
Solution: Use letters, digits, colons, underscores, or hyphens:
typescript
// Correct
new HosDriver({ instanceId: 'my-driver:001', ... })
new HosDriver({ instanceId: 'hue-bridge_01', ... })
// Invalid — contains spaces and special chars
new HosDriver({ instanceId: 'my driver @home', ... })Unregistered Session
Error: "Unregistered websocket session."
Detail: "driver.register is required before sending events."
Cause: Tried to send events (e.g. DEVICE_DISCOVERED) before completing registration.
Solution: Wait for the 'registered' event before calling sendEvent(). With autoRegister: true (default), the SDK handles registration automatically — listen for the registered event:
typescript
const driver = new HosDriver({ driverKey: 'MY_DRIVER', instanceId: 'my-driver:001' });
// Wait for registered before sending events
driver.on('registered', () => {
driver.sendEvent('DEVICE_DISCOVERED', {
device_id: 'my-device-001',
data: { name: 'My Device', deviceType: 'light' },
});
});
driver.connect();Message Errors
Invalid JSON
Error: "Invalid JSON"
Cause: The WebSocket message was not valid JSON.
Solution: This should not happen when using the SDK — sendEvent() serializes messages automatically with JSON.stringify(). If sending raw WebSocket messages, ensure the payload is valid JSON:
typescript
// Correct — SDK handles serialization
driver.sendEvent('STATE_UPDATE', { device_id: 'my-device', data: { power: true } });
// If sending raw — must be valid JSON
ws.send(JSON.stringify({ event: 'STATE_UPDATE', device_id: 'my-device', data: { power: true } }));Invalid Event Payload
Error: "Invalid {EVENT_NAME} payload."
Common details:
"device_id is required."— missingdevice_idfield"data must be a non-null object."— missing or invaliddatafield
Cause: The event message is missing required fields.
Solution: Every event except DEVICE_REMOVED requires both device_id (string) and data (object). Check that you pass both to sendEvent():
typescript
driver.sendEvent('STATE_UPDATE', {
device_id: 'my-device-001', // required
data: { power: true }, // required
});DEVICE_REMOVED only requires device_id:
typescript
driver.sendEvent('DEVICE_REMOVED', {
device_id: 'my-device-001',
});Connection Errors
See Getting Started to verify your environment setup before debugging connection issues.
Connection Refused
Symptom: 'error' event fires with ECONNREFUSED
Cause: HOS server is not running, or the WebSocket URL/port is wrong.
Solution:
- Verify the HOS server is running (
npm run serverfrom the repo root) - Check
HOS_WS_URL— default isws://localhost:8080/driver - Verify the port matches the server's
DRIVER_WS_PORTconfiguration
typescript
// Check your wsUrl
const driver = new HosDriver({
driverKey: 'MY_DRIVER',
instanceId: 'my-driver:001',
wsUrl: process.env.HOS_WS_URL ?? 'ws://localhost:8080/driver',
});
driver.on('error', (err) => {
console.error('Connection error:', err.message);
// ECONNREFUSED means server is not reachable
});Session Replaced (Close Code 4001)
Symptom: 'disconnected' event with code: 4001, followed by 'error' event with "Session replaced by new connection"
Cause: Another driver instance connected with the same driverKey + instanceId combination. The server closed the older session.
Solution: Each running instance MUST have a unique instanceId. If running multiple instances of the same driver type, use distinct instanceIds:
typescript
// Instance 1
new HosDriver({ driverKey: 'HUE_BRIDGE', instanceId: 'hue-bridge:001' })
// Instance 2
new HosDriver({ driverKey: 'HUE_BRIDGE', instanceId: 'hue-bridge:002' })Note: The SDK does NOT reconnect after a 4001 close — this is intentional. A 4001 indicates a configuration conflict, not a transient network error.
Reconnect Behavior
Symptom: Driver keeps disconnecting and reconnecting
The SDK reconnects automatically with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | 1s (+/-10% jitter) |
| 2 | 2s (+/-10% jitter) |
| 3 | 4s (+/-10% jitter) |
| 4 | 8s (+/-10% jitter) |
| 5+ | 30s (maximum, +/-10% jitter) |
The delay resets to 1s after a successful connection is established.
To disable reconnect:
typescript
const driver = new HosDriver({
driverKey: 'MY_DRIVER',
instanceId: 'my-driver:001',
reconnect: false,
});To adjust timing:
typescript
const driver = new HosDriver({
driverKey: 'MY_DRIVER',
instanceId: 'my-driver:001',
reconnectBaseMs: 2000, // Start at 2s instead of 1s
reconnectMaxMs: 60000, // Cap at 60s instead of 30s
});If the driver cannot reconnect, verify the server is still running and that no authentication or session conflict (4001) has occurred.
What's Next
- Getting Started — If you haven't run a driver yet, start here
- Driver Lifecycle — Full lifecycle walkthrough including reconnection behavior
- API Reference — REST endpoints, SSE events, and WebSocket protocol details