666ghj/MiroFish · error · StarHistoryError
Star count file is missing or unsafe
Error message
Star count file is missing or unsafe
What it means
load_star_count_file opens the count file with O_RDONLY|O_NOFOLLOW; any OSError from os.open — including missing file, ELOOP (final component is a symlink, which O_NOFOLLOW rejects), EACCES — is reported as 'Star count file is missing or unsafe'. The wording reflects that the reader deliberately cannot distinguish benign absence from a symlink attack.
Source
Thrown at scripts/star_history.py:519
except FileNotFoundError as exc:
raise StarHistoryError(f"{label} is missing") from exc
except OSError as exc:
raise StarHistoryError(f"could not read {label}") from exc
if len(payload) > limit:
raise StarHistoryError(f"{label} exceeded the size limit")
return payload
def load_star_count_file(path: Path) -> int:
"""Read a tiny, symlink-safe decimal count produced by the fetch-only step."""
flags = os.O_RDONLY
if hasattr(os, "O_NOFOLLOW"):
flags |= os.O_NOFOLLOW
try:
descriptor = os.open(path, flags)
except OSError as exc:
raise StarHistoryError("Star count file is missing or unsafe") from exc
try:
metadata = os.fstat(descriptor)
if not stat.S_ISREG(metadata.st_mode):
raise StarHistoryError("Star count file is not a regular file")
payload = os.read(descriptor, MAX_COUNT_FILE_BYTES + 1)
except OSError as exc:
raise StarHistoryError("could not read Star count file") from exc
finally:
os.close(descriptor)
if len(payload) > MAX_COUNT_FILE_BYTES:
raise StarHistoryError("Star count file exceeded the size limit")
if not re.fullmatch(rb"(?:0|[1-9][0-9]*)\n?", payload):
raise StarHistoryError("Star count file must contain one decimal integer")
count = int(payload)
if count > MAX_STAR_COUNT:
raise StarHistoryError("Star count exceeded the supported range")
return countView on GitHub (pinned to b5b53acc57)
Solutions
- Run the fetch-only step first so the count file exists as a regular file
- readlink the path — if it is a symlink, replace it with the real file
- Verify the exact path/working directory passed to load_star_count_file
- Transfer the artifact between pipeline stages if fetch and render run apart
Example fix
# before render(count=load_star_count_file(p)) # after subprocess.run(['python','scripts/fetch_star_count.py','--out',str(p)]) render(count=load_star_count_file(p))
Defensive patterns
Strategy: validation
Validate before calling
import os
def count_readable(p: Path) -> bool:
try:
st = os.lstat(p)
except OSError:
return False
import stat as s
return s.S_ISREG(st.st_mode) and os.access(p, os.R_OK) Try / catch
except StarHistoryError as e:
if str(e) == "Star count file is missing or unsafe":
run_fetch_step(); count = load_star_count_file(p) # produce it, retry
else: raise Prevention
- Make fetch a mandatory pipeline stage before render
- Transfer the count artifact between stages explicitly
- Never symlink the count file into place
- Validate the artifact in CI before consuming it
When it happens
Trigger: Calling load_star_count_file(path) before the fetch-only step (scripts/fetch_star_count.py) has written the count file, passing the wrong path, the file being a symlink (O_NOFOLLOW raises ELOOP), or lacking read permission.
Common situations: Split pipelines where fetch runs on one machine and render on another and the artifact was not transferred; count file symlinked from a shared cache; wrong working directory making the relative path miss.
Related errors
- output directory cannot be a symbolic link
- output file cannot be a symbolic link
- {label} is missing
- 模拟不存在: {simulation_id}
- 脚本不存在: {script_path}
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/8e67b667ca4b674f.
Report an issue: GitHub.