-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
Common issues and solutions when developing Home Assistant integrations.
Symptom:
ERROR: This package requires Python >=3.13
Solution:
# Check Python version
python --version # Should be 3.14.2+
# Use correct Python binary
python3.13 -m venv venvSymptom: Commands still use system Python
Solution:
# Linux/macOS
source venv/bin/activate
# Windows
venv\Scripts\activate.bat
# Verify activation (should see (venv) in prompt)
which python # Should show path in venv/Symptom:
ERROR: Could not find a version that satisfies the requirement
Solution:
# Update pip first
pip install --upgrade pip setuptools wheel
# Then install requirements
pip install -r requirements.txt
# If specific package fails, try:
pip install --no-cache-dir package-nameSymptom:
ModuleNotFoundError: No module named 'custom_components'
Solution:
This is already fixed in conftest.py, but if you see it:
# tests/conftest.py
import sys
from pathlib import Path
# Add custom_components to path
sys.path.insert(0, str(Path(__file__).parent.parent))Symptom:
RuntimeError: Async event loop is closed
Solution:
Use async def for test functions:
# ❌ WRONG
def test_something(hass):
hass.async_create_task(...)
# ✅ CORRECT
async def test_something(hass):
await hass.async_create_task(...)Symptom: Real API calls being made in tests
Solution:
Ensure mock is patched correctly:
# ❌ WRONG - patches wrong location
@patch("my_integration.api.MyClient")
def test_something(mock_client):
...
# ✅ CORRECT - patch where it's used
@patch("custom_components.my_integration.config_flow.MyClient")
def test_something(mock_client):
...Symptom:
error: Cannot find implementation or library stub for module named "homeassistant"
Solution:
Check mypy.ini:
[mypy-homeassistant.*]
ignore_missing_imports = TrueAlso verify:
# Clear mypy cache
rm -rf .mypy_cache/
# Re-run
mypy custom_components/my_integration/Symptom:
error: Argument 1 has incompatible type "dict[str, Any]"; expected "MyDataType"
Solution:
Define proper return type:
from typing import TypedDict
class DeviceData(TypedDict):
"""Type for device data."""
temperature: float
humidity: float
class MyCoordinator(DataUpdateCoordinator[dict[str, DeviceData]]):
"""Coordinator with typed data."""
async def _async_update_data(self) -> dict[str, DeviceData]:
"""Return typed data."""
...Symptom: Entity states never change
Causes:
- Coordinator not refreshing:
# ❌ WRONG - forgot first refresh
coordinator = MyCoordinator(hass, client)
hass.data[DOMAIN][entry.entry_id] = coordinator
# ✅ CORRECT
coordinator = MyCoordinator(hass, client)
await coordinator.async_config_entry_first_refresh()
hass.data[DOMAIN][entry.entry_id] = coordinator- Entities not using coordinator:
# ❌ WRONG - direct inheritance
class MySensor(SensorEntity):
...
# ✅ CORRECT - CoordinatorEntity
class MySensor(CoordinatorEntity[MyCoordinator], SensorEntity):
...- Data structure mismatch:
# Coordinator returns: {"device_1": {"temp": 20.5}}
# But entity expects: {"temp": 20.5}
# Fix: Access correctly
@property
def native_value(self):
return self.coordinator.data[self._device_id]["temp"]Symptom: All entities show as unavailable
Causes:
- Coordinator update failed:
# Check logs for UpdateFailed exceptions
# Fix the underlying issue (connection, auth, etc.)- Entity availability check too strict:
# ❌ WRONG - always returns False
@property
def available(self) -> bool:
return self._device_id in self.coordinator.data and self.coordinator.data[self._device_id].get("online")
# ✅ CORRECT - proper check
@property
def available(self) -> bool:
return super().available and self._device_id in self.coordinator.dataSymptom: Constant re-authentication requests
Cause: Not raising ConfigEntryAuthFailed
# ❌ WRONG
async def _async_update_data(self):
try:
return await self.client.async_get_data()
except AuthError:
raise UpdateFailed("Auth error") # Wrong exception!
# ✅ CORRECT
async def _async_update_data(self):
try:
return await self.client.async_get_data()
except AuthError as err:
raise ConfigEntryAuthFailed from errSymptom: CI fails but local passes
Cause: Different Ruff versions
Solution:
# Update local Ruff to match CI
pip install --upgrade ruff
# Run locally
ruff check .Symptom: Tests work locally but fail in GitHub Actions
Common causes:
- Platform-specific paths:
# ❌ WRONG - hardcoded path separator
path = "custom_components\\my_integration\\sensor.py"
# ✅ CORRECT - use Path
from pathlib import Path
path = Path("custom_components") / "my_integration" / "sensor.py"- Timezone-dependent tests:
# ❌ WRONG - uses local timezone
now = datetime.now()
# ✅ CORRECT - use UTC
from homeassistant.util import dt as dt_util
now = dt_util.utcnow()- Missing fixtures:
# Make sure conftest.py is in tests/
# CI runs in isolated environmentSymptom:
ImportError: cannot import name 'X' from partially initialized module
Solution:
Use TYPE_CHECKING:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .coordinator import MyCoordinator
class MyEntity:
"""Entity."""
def __init__(self, coordinator: MyCoordinator):
"""Initialize."""
self.coordinator = coordinatorSymptom:
ModuleNotFoundError: No module named 'custom_components.my_integration'
Solution:
# Ensure __init__.py exists
touch custom_components/__init__.py
touch custom_components/my_integration/__init__.pySymptom: Validation fails but error not displayed
Cause: Error key mismatch
# In config_flow.py
errors["base"] = "cannot_connect"
# In strings.json - must match!
{
"error": {
"cannot_connect": "Failed to connect"
}
}Symptom: Can't update entry, creates duplicate
Cause: Not setting unique ID
# ❌ WRONG - forgot unique ID
return self.async_create_entry(title="My Device", data=user_input)
# ✅ CORRECT
await self.async_set_unique_id(device_id)
self._abort_if_unique_id_configured()
return self.async_create_entry(title="My Device", data=user_input)Add to configuration.yaml:
logger:
default: warning
logs:
custom_components.my_integration: debug# Home Assistant logs
tail -f home-assistant.log | grep my_integration
# Or in HA UI:
# Settings → System → Logsasync def _async_update_data(self):
"""Fetch data."""
data = await self.client.async_get_data()
import pdb; pdb.set_trace() # Debugger breakpoint
return dataBefore asking:
- Check this troubleshooting guide
- Search HA Developer Docs
- Search GitHub Issues
When asking: Include:
- Error message (full traceback)
- What you tried
- Relevant code snippet
- HA version and Python version
Where to ask:
- Discussions - Questions
- Issues - Template bugs
- HA Discord - #devs_integrations channel
Avoid issues by following this checklist:
- Virtual environment activated before installing
- Tests run before committing
- Type checking passes (mypy)
- Linting passes (ruff)
- Used async for all I/O
- Proper error handling (ConfigEntryAuthFailed, UpdateFailed)
- Unique IDs set for entities
- Coordinator first refresh called
- Entity availability implemented
- Tested on clean environment
- Getting Started - Setup guide
- Development Guide - Development workflow
- Testing Guide - Testing best practices
- Quality Scale Guide - Quality standards