{"record":{"id":"22bae28e1418a218","repo":"home-assistant/core","slug":"no-path","errorCode":"no_path","errorMessage":"Can't write to directory {target}, no access to path!","messagePattern":"Can't write to directory (.+?), no access to path!","errorType":"validation","errorClass":"ServiceValidationError","httpStatus":null,"severity":"error","filePath":"homeassistant/components/blink/camera.py","lineNumber":169,"sourceCode":"\n    @override\n    def camera_image(\n        self, width: int | None = None, height: int | None = None\n    ) -> bytes | None:\n        \"\"\"Return a still image response from the camera.\"\"\"\n        try:\n            return self._camera.image_from_cache\n        except ChunkedEncodingError:\n            _LOGGER.debug(\"Could not retrieve image for %s\", self._camera.name)\n            return None\n        except TypeError:\n            _LOGGER.debug(\"No cached image for %s\", self._camera.name)\n            return None\n\n    async def save_recent_clips(self, file_path) -> None:\n        \"\"\"Save multiple recent clips to output directory.\"\"\"\n        if not self.hass.config.is_allowed_path(file_path):\n            raise ServiceValidationError(\n                translation_domain=DOMAIN,\n                translation_key=\"no_path\",\n                translation_placeholders={\"target\": file_path},\n            )\n\n        try:\n            await self._camera.save_recent_clips(output_dir=file_path)\n        except OSError as err:\n            raise ServiceValidationError(\n                translation_domain=DOMAIN,\n                translation_key=\"cant_write\",\n            ) from err\n        except UnauthorizedError as er:\n            self.coordinator.config_entry.async_start_reauth(self.hass)\n            raise ConfigEntryAuthFailed(\"Blink authorization failed\") from er\n\n    async def save_video(self, filename) -> None:\n        \"\"\"Handle save video service calls.\"\"\"","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/home-assistant/core/blob/58a3fdb3ea0538617f0a07efcfba6294de64fd59/homeassistant/components/blink/camera.py#L151-L187","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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)"],"exampleFix":"# before\nservice_data:\n  file_path: /tmp/blink_clips\n# after\nservice_data:\n  file_path: /config/www/blink_clips","handlingStrategy":"validation","validationCode":"# Before calling the service, confirm the path is allowlisted\nimport os\nfrom homeassistant.config import async_hass_config  # or use hass directly\n\nallowed = hass.config.is_allowed_path(file_path) and os.path.isdir(file_path)\nif not allowed:\n    # surface a friendly message / pick a default like <config>/www/clips\n    file_path = os.path.join(hass.config.config_dir, \"www\", \"clips\")","typeGuard":null,"tryCatchPattern":"try:\n    await hass.services.async_call(\n        \"blink\", \"save_recent_clips\", {\"file_path\": path}, blocking=True\n    )\nexcept HomeAssistantError as err:\n    # ServiceValidationError carries the translation key; check for no_path\n    _LOGGER.warning(\"blink save_recent_clips rejected: %s\", err)","preventionTips":["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"],"tags":["blink","service-validation","filesystem","allowlist","camera"],"backgroundTag":null,"analyzedSha":"58a3fdb3ea0538617f0a07efcfba6294de64fd59","analyzedAt":"2026-08-14T20:54:38.818Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}