home-assistant/core · error · ValueError

Invalid MAC address

Error message

Invalid MAC address

What it means

Plain ValueError('Invalid MAC address') from the mac_address helper: it accepts MACs of length 17 (colon/dash separated pairs), 14, or 12 hex chars, normalizes them, then calls bytes.fromhex. Anything else — wrong length or non-hex content — raises. It is used to parse device MACs (e.g. from config entries or discovery) before .hex() unique-id generation.

Source

Thrown at homeassistant/components/broadlink/helpers.py:29

def data_packet(value):
    """Decode a data packet given for a Broadlink remote."""
    value = cv.string(value)
    extra = len(value) % 4
    if extra > 0:
        value = value + ("=" * (4 - extra))
    return b64decode(value)


def mac_address(mac):
    """Validate and convert a MAC address to bytes."""
    mac = cv.string(mac)
    if len(mac) == 17:
        mac = "".join(mac[i : i + 2] for i in range(0, 17, 3))
    elif len(mac) == 14:
        mac = "".join(mac[i : i + 4] for i in range(0, 14, 5))
    elif len(mac) != 12:
        raise ValueError("Invalid MAC address")
    return bytes.fromhex(mac)


def format_mac(mac):
    """Format a MAC address."""
    return ":".join([format(octet, "02x") for octet in mac])


def import_device(hass, host):
    """Create a config flow for a device."""
    configured_hosts = {
        entry.data.get(CONF_HOST) for entry in hass.config_entries.async_entries(DOMAIN)
    }

    if host not in configured_hosts:
        task = hass.config_entries.flow.async_init(
            DOMAIN,
            context={"source": config_entries.SOURCE_IMPORT},

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Re-enter the MAC exactly as printed on the device label, e.g. AA:BB:CC:DD:EE:FF (17 chars) or 12 bare hex digits.
  2. Strip whitespace/newlines before passing the value.
  3. Verify length: 12, 14, or 17 characters only; separators must be consistent so normalization yields valid hex.
  4. If it comes from discovery data, capture the raw payload and open a core issue for the device model.

Example fix

// before
mac_bytes = mac_address("AA:BB:CC:DD:EE")  # too short

// after
mac_bytes = mac_address("AA:BB:CC:DD:EE:FF")
Defensive patterns

Strategy: validation

Validate before calling

import re

def is_valid_broadlink_mac(mac: str) -> bool:
    """True for 12/14/17-char strings whose stripped form is pure hex."""
    if not isinstance(mac, str):
        return False
    stripped = re.sub(r"[:.\-\s]", "", mac)
    return len(mac) in (12, 14, 17) and re.fullmatch(r"[0-9a-fA-F]+", stripped) is not None and len(stripped) == 12

Type guard

def is_mac_string(value: object) -> bool:
    """Narrow arbitrary config input to an acceptable MAC string."""
    return isinstance(value, str) and bool(re.fullmatch(r"[0-9A-Fa-f:.\-\s]{12,17}", value))

Try / catch

try:
    mac_bytes = mac_address(user_input[CONF_MAC])
except ValueError:
    errors[CONF_MAC] = "invalid_mac"  # show field error in the form instead of crashing

Prevention

When it happens

Trigger: mac_address() receives a string shorter/longer than 12/14/17 characters, or containing non-hex characters (e.g. 'ZZ:...', or a 16-char truncated MAC, or empty string). Callers include import_device / device setup paths that parse user-supplied or discovery-supplied hosts.

Common situations: Manual config with a typo'd MAC, discovery payload with an atypical separator pattern whose stripped length is not 12/14/17, copy-paste including whitespace, or a None/empty value passed by a broken caller.

Related errors


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