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
- Use a path under an allowlisted directory, e.g. /config/www/clips or your configured media directory
- If a custom directory is required, add it via allowlist_external_dirs in configuration.yaml (or the default_dirs/media UI setting)
- Pass an absolute path; relative paths are not expanded to the config directory
- 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
- Standardize automations on one allowlisted base directory constant
- Add custom directories to allowlist_external_dirs once in configuration.yaml instead of passing ad-hoc paths
- Always pass absolute paths to blink media services
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.