home-assistant/core · warning · UpdateFailed
No data returned from Azure DevOps
Error message
No data returned from Azure DevOps
What it means
Raised as UpdateFailed('No data returned from Azure DevOps') by the ado_exception_none_handler decorator when a wrapped coordinator method returns None instead of raising — the aiohttp call succeeded at the transport level but the DevOps client produced no object (empty/empty-looking response). Separately, aiohttp.ClientError is converted to a message-less UpdateFailed.
Source
Thrown at homeassistant/components/azure_devops/coordinator.py:44
from .data import AzureDevOpsData
BUILDS_QUERY: Final = "?queryOrder=queueTimeDescending&maxBuildsPerDefinition=1"
IGNORED_CATEGORIES: Final[list[Category]] = [Category.COMPLETED, Category.REMOVED]
type AzureDevOpsConfigEntry = ConfigEntry[AzureDevOpsDataUpdateCoordinator]
def ado_exception_none_handler(func: Callable) -> Callable:
"""Handle exceptions or None to always return a value or raise."""
async def handler(*args, **kwargs):
try:
response = await func(*args, **kwargs)
except aiohttp.ClientError as exception:
raise UpdateFailed from exception
if response is None:
raise UpdateFailed("No data returned from Azure DevOps")
return response
return handler
class AzureDevOpsDataUpdateCoordinator(DataUpdateCoordinator[AzureDevOpsData]):
"""Class to manage and fetch Azure DevOps data."""
client: DevOpsClient
config_entry: AzureDevOpsConfigEntry
organization: str
project: Project
def __init__(
self,
hass: HomeAssistant,
config_entry: AzureDevOpsConfigEntry,View on GitHub (pinned to 58a3fdb3ea)
Solutions
- Verify the project identifier in the config entry matches an existing project in the Azure DevOps organization.
- Re-create the PAT with the correct scopes (Code Read, Build Read, etc.) and re-authenticate.
- Confirm the organization name is correct and the account can see the project.
- Watch for the sibling case: if UpdateFailed has no message text, the underlying cause was an aiohttp.ClientError — check network/proxy.
Defensive patterns
Strategy: validation
Validate before calling
async def project_exists(client, organization: str, project: str) -> bool:
projects = await client.get_projects(organization)
return any(p.name.lower() == project.lower() or p.id == project for p in projects or [])
Type guard
def has_data(response) -> bool:
return response is not None
Try / catch
from homeassistant.helpers.update_coordinator import UpdateFailed
import aiohttp
try:
data = await coordinator.async_refresh()
except UpdateFailed as err:
if not str(err): # empty message == aiohttp.ClientError underneath
check_network_proxy()
else: # 'No data returned' == empty response: check project/PAT scope
check_project_and_pat() Prevention
- Confirm project and organization names case-sensitively against Azure DevOps.
- Scope PATs to Code (Read), Build (Read), Project and Team (Read).
- Watch for the message-less variant — it signals a transport-level ClientError instead.
When it happens
Trigger: get_project()/get_builds()/get_pull_request() etc. return None: project name or ID not found in the organization, wrong PAT scope so the API returns an empty payload, or the organization/project renamed so lookups resolve to nothing.
Common situations: Project was renamed or deleted; PAT lacks the required scope (e.g. Build/Code Read); organization name typo'd; personal access token expired in a way that yields empty responses instead of an auth error.
Related errors
- authentication_failed
- Unable find multi-factor auth module: {mfa_module_id}
- update_error
- Failed to communicate with device.
- Failed to connect
AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14).
Data as JSON: /api/errors/3ef2142297b94275.
Report an issue: GitHub.