home-assistant/core · error · ServiceValidationError

channel_not_found

channel_not_found

Error message

There is no {channel_type} channel at this site.

What it means

ServiceValidationError with translation key amberelectric/channel_not_found, raised by get_forecasts() when the requested channel_type (general, controlled_load, or feed_in) has no key in data['forecasts'] — the site has no forecast intervals for that channel, so the forecast service cannot return anything.

Source

Thrown at homeassistant/components/amberelectric/services.py:44

from .coordinator import AmberConfigEntry
from .helpers import format_cents_to_dollars, normalize_descriptor

GET_FORECASTS_SCHEMA = vol.Schema(
    {
        ATTR_CONFIG_ENTRY_ID: ConfigEntrySelector({"integration": DOMAIN}),
        ATTR_CHANNEL_TYPE: vol.In(
            [GENERAL_CHANNEL, CONTROLLED_LOAD_CHANNEL, FEED_IN_CHANNEL]
        ),
    }
)


def get_forecasts(channel_type: str, data: dict) -> list[JsonValueType]:
    """Return an array of forecasts."""
    results: list[JsonValueType] = []

    if channel_type not in data["forecasts"]:
        raise ServiceValidationError(
            translation_domain=DOMAIN,
            translation_key="channel_not_found",
            translation_placeholders={"channel_type": channel_type},
        )

    intervals = data["forecasts"][channel_type]

    for interval in intervals:
        datum = {}
        datum["duration"] = interval.duration
        datum["date"] = interval.var_date.isoformat()
        datum["nem_date"] = interval.nem_time.isoformat()
        datum["per_kwh"] = format_cents_to_dollars(interval.per_kwh)
        if interval.channel_type == ChannelType.FEEDIN:
            datum["per_kwh"] = datum["per_kwh"] * -1
        datum["spot_per_kwh"] = format_cents_to_dollars(interval.spot_per_kwh)
        datum["start_time"] = interval.start_time.isoformat()
        datum["end_time"] = interval.end_time.isoformat()

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Request forecasts only for channels your Amber site actually has (check the Amber app tariff channels)
  2. Use 'general' — every site with the integration set up must have it
  3. Ensure the integration has completed at least one successful data update before calling the forecast service
  4. Reconfigure the site selection if the wrong site was chosen

Example fix

// before
action:
  domain: amberelectric
  data:
    channel_type: controlled_load  # site has no controlled load channel
// after
action:
  domain: amberelectric
  data:
    channel_type: general  # channel present in data["forecasts"]
Defensive patterns

Strategy: validation

Validate before calling

if channel_type not in data["forecasts"]:
    _LOGGER.warning(
        "Channel %s has no forecasts (available: %s)",
        channel_type, list(data["forecasts"]),
    )
    return

Type guard

def has_forecast_channel(data: dict, channel_type: str) -> bool:
    """True when the coordinator data has forecasts for channel_type."""
    return channel_type in data.get("forecasts", {})

Try / catch

try:
    await hass.services.async_call(DOMAIN, "get_forecasts", service_data, blocking=True)
except ServiceValidationError as err:
    if err.translation_key == "channel_not_found":
        _LOGGER.warning("Site has no %s channel; use a channel your tariff provides", channel_type)

Prevention

When it happens

Trigger: Calling the get_forecasts service with ATTR_CHANNEL_TYPE=controlled_load or feed_in on a site whose coordinator data contains no forecast entries for that channel (only general present), because the Amber tariff lacks that channel.

Common situations: Users without a controlled-load or solar feed-in tariff requesting those forecast services, or calling the service before the coordinator has fetched data containing the channel.

Related errors


AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14). Data as JSON: /api/errors/6006ecd2571e7a71. Report an issue: GitHub.