{"record":{"id":"62164b130772b7ae","repo":"666ghj/MiroFish","slug":"star-count-file-is-not-a-regular-file","errorCode":null,"errorMessage":"Star count file is not a regular file","messagePattern":"Star count file is not a regular file","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":523,"sourceCode":"    if len(payload) > limit:\n        raise StarHistoryError(f\"{label} exceeded the size limit\")\n    return payload\n\n\ndef load_star_count_file(path: Path) -> int:\n    \"\"\"Read a tiny, symlink-safe decimal count produced by the fetch-only step.\"\"\"\n\n    flags = os.O_RDONLY\n    if hasattr(os, \"O_NOFOLLOW\"):\n        flags |= os.O_NOFOLLOW\n    try:\n        descriptor = os.open(path, flags)\n    except OSError as exc:\n        raise StarHistoryError(\"Star count file is missing or unsafe\") from exc\n    try:\n        metadata = os.fstat(descriptor)\n        if not stat.S_ISREG(metadata.st_mode):\n            raise StarHistoryError(\"Star count file is not a regular file\")\n        payload = os.read(descriptor, MAX_COUNT_FILE_BYTES + 1)\n    except OSError as exc:\n        raise StarHistoryError(\"could not read Star count file\") from exc\n    finally:\n        os.close(descriptor)\n\n    if len(payload) > MAX_COUNT_FILE_BYTES:\n        raise StarHistoryError(\"Star count file exceeded the size limit\")\n    if not re.fullmatch(rb\"(?:0|[1-9][0-9]*)\\n?\", payload):\n        raise StarHistoryError(\"Star count file must contain one decimal integer\")\n    count = int(payload)\n    if count > MAX_STAR_COUNT:\n        raise StarHistoryError(\"Star count exceeded the supported range\")\n    return count\n\n\ndef load_state(workspace: Path, require_canonical: bool = True) -> dict[str, Any]:\n    state_path = _safe_target(workspace, STATE_RELATIVE, create_parent=False)","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L505-L541","documentation":"After a successful O_NOFOLLOW open, load_star_count_file fstats the descriptor and requires a regular file (stat.S_ISREG). FIFOs, sockets, character/block devices, and directories are rejected so the reader never blocks on a fifo or trust device semantics for a tiny decimal count.","triggerScenarios":"The path handed to load_star_count_file is a named pipe (mkfifo), a unix socket, /dev-style device node, or a directory. Note O_NOFOLLOW only guards the final symlink hop, so other non-regular types reach this check.","commonSituations":"A stale fifo left by earlier tooling at the count path, tests using tmp_path fixtures that create directories where a file is expected, or deliberately crafted inputs in security review.","solutions":["stat the path: it should be '-rw-' not 'p','s','c','b', or 'd'","Remove the non-regular file: rm / path-to-object","Re-run the fetch step to write a plain regular file","If this appears in tests, assert the fixture creates a file, not a directory"],"exampleFix":"# before\nos.mkfifo(count_path)          # test fixture mistake\n# after\ncount_path.write_text('1234\\n')  # regular file","handlingStrategy":"type-guard","validationCode":"import stat, os\nst = os.lstat(p)\nif not stat.S_ISREG(st.st_mode):\n    raise RuntimeError(f'count path is not a regular file: mode {oct(st.st_mode)}')","typeGuard":"def is_regular_file(p: Path) -> bool:\n    try:\n        return stat.S_ISREG(os.lstat(p).st_mode)\n    except OSError:\n        return False","tryCatchPattern":null,"preventionTips":["Fixtures must create files, not fifos/dirs","rm stray fifos at artifact paths","Use lstat (not stat) so symlinks are caught as non-regular too","Keep artifact directories owned by the pipeline only"],"tags":["filesystem","validation","state"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}