home-assistant/core · error · ServiceValidationError

no_path

no_path

Error message

Can't write to directory {target}, no access to path!

What it means

Raised as a ServiceValidationError when the blink.save_recent_clips service is called with a file_path that is not inside Home Assistant's allowlisted directories. hass.config.is_allowed_path() checks the path against allowlist_external_dirs; outside those roots the write is refused before any network or disk I/O happens. The translation key 'no_path' surfaces the message 'Can't write to directory {target}, no access to path!' to the service caller.

Source

Thrown at homeassistant/components/blink/camera.py:169

    @override
    def camera_image(
        self, width: int | None = None, height: int | None = None
    ) -> bytes | None:
        """Return a still image response from the camera."""
        try:
            return self._camera.image_from_cache
        except ChunkedEncodingError:
            _LOGGER.debug("Could not retrieve image for %s", self._camera.name)
            return None
        except TypeError:
            _LOGGER.debug("No cached image for %s", self._camera.name)
            return None

    async def save_recent_clips(self, file_path) -> None:
        """Save multiple recent clips to output directory."""
        if not self.hass.config.is_allowed_path(file_path):
            raise ServiceValidationError(
                translation_domain=DOMAIN,
                translation_key="no_path",
                translation_placeholders={"target": file_path},
            )

        try:
            await self._camera.save_recent_clips(output_dir=file_path)
        except OSError as err:
            raise ServiceValidationError(
                translation_domain=DOMAIN,
                translation_key="cant_write",
            ) from err
        except UnauthorizedError as er:
            self.coordinator.config_entry.async_start_reauth(self.hass)
            raise ConfigEntryAuthFailed("Blink authorization failed") from er

    async def save_video(self, filename) -> None:
        """Handle save video service calls."""

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Use a path under an allowlisted directory, e.g. /config/www/clips or your configured media directory
  2. If a custom directory is required, add it via allowlist_external_dirs in configuration.yaml (or the default_dirs/media UI setting)
  3. Pass an absolute path; relative paths are not expanded to the config directory
  4. Check the path spelling and that symlinks resolve inside the allowlist (is_allowed_path uses realpath)

Example fix

# before
service_data:
  file_path: /tmp/blink_clips
# after
service_data:
  file_path: /config/www/blink_clips
Defensive patterns

Strategy: validation

Validate before calling

# Before calling the service, confirm the path is allowlisted
import os
from homeassistant.config import async_hass_config  # or use hass directly

allowed = hass.config.is_allowed_path(file_path) and os.path.isdir(file_path)
if not allowed:
    # surface a friendly message / pick a default like <config>/www/clips
    file_path = os.path.join(hass.config.config_dir, "www", "clips")

Try / catch

try:
    await hass.services.async_call(
        "blink", "save_recent_clips", {"file_path": path}, blocking=True
    )
except HomeAssistantError as err:
    # ServiceValidationError carries the translation key; check for no_path
    _LOGGER.warning("blink save_recent_clips rejected: %s", err)

Prevention

When it happens

Trigger: Calling the blink save_recent_clips service action with file_path set to an absolute path outside the allowlist, a relative path (which resolves against the HA process cwd, not the config dir), or a path with a typo in the allowed prefix. is_allowed_path() returns False and the error is raised immediately in save_recent_clips().

Common situations: Users pass /tmp/clips or ~/Movies instead of <config>/www or another allowlisted dir; default allowlist only contains the media and config directories; relative paths like 'clips/' fail because they do not match an absolute allowlisted prefix.

Related errors


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