666ghj/MiroFish · error · StarHistoryError
workspace is not a directory
Error message
workspace is not a directory
What it means
Raised by _safe_workspace() when the workspace path resolves successfully but is not a directory (root.is_dir() is false) — e.g. it is a regular file, fifo, or device. The workspace is expected to be the containing directory under which output paths are confined.
Source
Thrown at scripts/star_history.py:460
raise StarHistoryError("first snapshot cannot predate reconstruction")
if previous_day is not None and previous_day >= first_snapshot.date():
raise StarHistoryError("reconstruction dates must predate snapshots")
def canonical_state_bytes(state: Mapping[str, Any]) -> bytes:
validate_state(state)
return (
json.dumps(state, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
).encode("utf-8")
def _safe_workspace(workspace: Path) -> Path:
try:
root = workspace.resolve(strict=True)
except OSError as exc:
raise StarHistoryError("workspace does not exist") from exc
if not root.is_dir():
raise StarHistoryError("workspace is not a directory")
return root
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:View on GitHub (pinned to b5b53acc57)
Solutions
- Point the workspace at the directory that should contain outputs, not at a file
- Remove the stray file occupying the workspace path if the directory was intended
- Re-check the CLI/config argument order and semantics
Example fix
# before
workspace = Path("out/star-history.json") # this is a file
# after
workspace = Path("out") # directory; pass the file name as the relative target Defensive patterns
Strategy: validation
Validate before calling
workspace = Path(config["workspace"])
if not workspace.is_dir():
raise NotADirectoryError(f"workspace is not a directory: {workspace}") Type guard
from pathlib import Path
def is_workspace_dir(workspace: Path) -> bool:
return workspace.is_dir() Try / catch
try:
write_output(workspace, relative, data)
except StarHistoryError as exc:
if "workspace is not a directory" in str(exc):
# fix configuration: point workspace at the parent directory
... Prevention
- Keep workspace (directory) and output target (relative filename) as separate config values
- Document the distinction in the tool's config schema
- Add a startup assertion that the workspace is a directory
When it happens
Trigger: Calling an output-writing code path with a workspace Path that names an existing file (e.g. pointing the workspace at the state JSON itself instead of its directory).
Common situations: Configuration confusion between the output file path and its parent directory; a file created at the location where the workspace directory was expected; swapped CLI arguments for workspace vs. file.
Related errors
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/5ce7aa72fb8f26fb.
Report an issue: GitHub.