affaan-m/ECC · error · ValueError
output parent directory must already exist
Error message
output parent directory must already exist
What it means
When the output root does not exist, _SafeOutput will create it (mode 0o700) but deliberately refuses to create parent directories. If the immediate parent of the requested root is not an existing directory, __init__ raises this error so that path assumptions and permissions stay explicit and no accidental deep trees are created.
Solutions
- Create the parent directory first: Path('a/b').mkdir(parents=True, exist_ok=True) before constructing _SafeOutput
- Verify/fix the output path spelling in your config or CLI arguments
- Have the calling script (e.g. run_workflow's CLI entry) prepare the base output directory before invoking _SafeOutput
- Run from the intended working directory so relative paths resolve to existing parents
Example fix
# before
out = _SafeOutput(Path('artifacts/run1')) # artifacts/ does not exist
# after
Path('artifacts').mkdir(parents=True, exist_ok=True)
out = _SafeOutput(Path('artifacts/run1')) Defensive patterns
Strategy: validation
Validate before calling
def ensure_parent_exists(root):
if not root.parent.is_dir():
root.parent.mkdir(parents=True, exist_ok=True) Type guard
def parent_ready(p) -> bool:
return p.parent.is_dir() Try / catch
try:
out = _SafeOutput(root)
except ValueError as e:
if 'parent directory must already exist' in str(e):
root.parent.mkdir(parents=True, exist_ok=True)
out = _SafeOutput(root)
else:
raise Prevention
- Create the base output directory in your pipeline bootstrap step
- Double-check spelling of configured output paths
- Use absolute paths to avoid cwd surprises in CI
- Run a path dry-run (parent check) before expensive work
When it happens
Trigger: _SafeOutput(Path('a/b/c')) where 'a/b' or 'a/b/c''s parent does not exist; passing outputs/<run-id>/... when outputs/ was deleted; a typo in the parent directory name.
Common situations: CI workspaces where prior artifact dirs were cleaned before the run; user-supplied output paths with non-existent nested parents; typos like 'ouputs/run1'.
Related errors
- all overlays must be readable local files
- all takes must be readable local files
- artifact path must stay beneath output root
- base video must be a readable local file
- Failed to create directory
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/83a51196f28fcf78.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/workflow.py:183
return float(duration)
class _SafeOutput:
"""Descriptor-bound output tree with no-follow traversal and atomic writes."""
def __init__(self, root: Path) -> None:
self._root_fd = -1
if not hasattr(os, "O_NOFOLLOW") or not hasattr(os, "O_DIRECTORY"):
raise RuntimeError("secure output requires O_NOFOLLOW and O_DIRECTORY")
if root.exists() or root.is_symlink():
metadata = root.lstat()
if stat.S_ISLNK(metadata.st_mode):
raise ValueError("output root must not be a symlink")
if not stat.S_ISDIR(metadata.st_mode):
raise ValueError("output root must be a directory")
else:
if not root.parent.is_dir():
raise ValueError("output parent directory must already exist")
root.mkdir(mode=0o700)
self.root = root
self._root_fd = os.open(root, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
self._written: list[str] = []
def close(self) -> None:
if self._root_fd >= 0:
os.close(self._root_fd)
self._root_fd = -1
def __del__(self) -> None:
self.close()
def _open_dir(self, parts: tuple[str, ...], *, create: bool) -> int:
current = os.dup(self._root_fd)
try:
for part in parts:
if not part or part in {".", ".."} or "/" in part:View on GitHub (pinned to 8321021c54)