666ghj/MiroFish · error · StarHistoryError
could not create output directory
Error message
could not create output directory
What it means
Raised by _safe_target when Path.mkdir(parents=True, exist_ok=True) on the output's parent directory raises OSError. The raw OS error is chained (__cause__) so the underlying errno is preserved in the traceback.
Source
Thrown at scripts/star_history.py:481
def _safe_target(workspace: Path, relative: Path, create_parent: bool) -> Path:
root = _safe_workspace(workspace)
if relative.is_absolute() or ".." in relative.parts:
raise StarHistoryError("output path escaped the workspace")
current = root
for part in relative.parts[:-1]:
current = current / part
if current.is_symlink():
raise StarHistoryError("output directory cannot be a symbolic link")
target = root / relative
if target.is_symlink():
raise StarHistoryError("output file cannot be a symbolic link")
if create_parent:
try:
target.parent.mkdir(parents=True, exist_ok=True)
except OSError as exc:
raise StarHistoryError("could not create output directory") from exc
current = root
for part in relative.parts[:-1]:
current = current / part
if current.is_symlink():
raise StarHistoryError("output directory cannot be a symbolic link")
if target.is_symlink():
raise StarHistoryError("output file cannot be a symbolic link")
try:
resolved_parent = target.parent.resolve(strict=False)
resolved_parent.relative_to(root)
except (OSError, ValueError) as exc:
raise StarHistoryError("output path escaped the workspace") from exc
return resolved_parent / target.name
def _read_limited(path: Path, limit: int, label: str) -> bytes:
try:
with path.open("rb") as handle:View on GitHub (pinned to b5b53acc57)
Solutions
- Inspect exc.__cause__ from the StarHistoryError to get the errno
- Ensure the invoking user has write permission on the workspace (or run with appropriate ownership)
- Remove any regular file occupying the directory path: find . -name 'star-history' -type f
- Free disk space / raise quota, or point the workspace at a writable location
Example fix
# before: a file blocks the directory path .github/star-history (regular file) # after rm .github/star-history && mkdir -p .github/star-history
Defensive patterns
Strategy: try-catch
Validate before calling
parent = (ws / rel).parent
if parent.exists() and not parent.is_dir():
raise RuntimeError(f"{parent} exists but is not a directory")
import os
if not os.access(ws, os.W_OK):
raise RuntimeError("workspace not writable") Try / catch
try:
_safe_target(ws, rel, create_parent=True)
except StarHistoryError as e:
if str(e) == "could not create output directory" and e.__cause__:
errno = e.__cause__.errno # EACCES/ENOSPC/EEXIST/EROFS -> targeted fix
raise Prevention
- Check writable workspace and free disk before runs
- Never create files named like the state directory
- Run read/write steps as the same user
- df -h before large pipeline stages
When it happens
Trigger: Calling _safe_target(workspace, relative, create_parent=True) (i.e. save paths) when the parent chain cannot be created: EACCES/EPERM on the workspace dir, ENOSPC (disk full), EEXIST because a path component already exists as a regular file (e.g. a file literally named '.github/star-history'), EROFS on a read-only filesystem, or EDQUOT quota exceeded.
Common situations: Running the tool in CI as a non-owner user against a checked-out repo, disk-full build agents, a stray file named like the state directory, or containers with a read-only layer at that path.
Related errors
- could not read {label}
- output directory cannot be a symbolic link
- output file cannot be a symbolic link
- Star count file is not a regular file
- could not atomically replace Star History outputs
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/c2dd49827db6a339.
Report an issue: GitHub.