{"record":{"id":"8554fb3ca8bfe3a0","repo":"Panniantong/Agent-Reach","slug":"target","errorCode":null,"errorMessage":"读取目标不是常规文件：{target}","messagePattern":"读取目标不是常规文件：(.+?)","errorType":"exception","errorClass":"PrivatePathError","httpStatus":null,"severity":"error","filePath":"agent_reach/utils/paths.py","lineNumber":164,"sourceCode":"    if max_bytes < 0:\n        raise ValueError(\"max_bytes must be non-negative\")\n\n    target = ensure_no_symlink_path(path, \"读取路径\")\n    flags = (\n        os.O_RDONLY\n        | getattr(os, \"O_NOFOLLOW\", 0)\n        | getattr(os, \"O_NONBLOCK\", 0)\n        | getattr(os, \"O_CLOEXEC\", 0)\n    )\n    try:\n        fd = os.open(target, flags)\n    except FileNotFoundError:\n        return None\n\n    try:\n        file_stat = os.fstat(fd)\n        if not stat.S_ISREG(file_stat.st_mode):\n            raise PrivatePathError(f\"读取目标不是常规文件：{target}\")\n        if file_stat.st_size > max_bytes:\n            raise PrivatePathError(f\"读取目标超过大小上限：{target}\")\n\n        chunks = []\n        remaining = max_bytes + 1\n        while remaining:\n            chunk = os.read(fd, remaining)\n            if not chunk:\n                break\n            chunks.append(chunk)\n            remaining -= len(chunk)\n        payload = b\"\".join(chunks)\n        if len(payload) > max_bytes:\n            raise PrivatePathError(f\"读取目标超过大小上限：{target}\")\n        ensure_no_symlink_path(target, \"读取路径\")\n    finally:\n        os.close(fd)\n    return payload.decode(encoding)","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/Panniantong/Agent-Reach/blob/93ae1d18c37b707dec053c7c4f9d91cd8ef8943d/agent_reach/utils/paths.py#L146-L182","documentation":"Raised by the O_NOFOLLOW private file reader when the opened file descriptor's fstat shows the target is not a regular file (not S_ISREG). The file was opened with O_NOFOLLOW so a symlink final component would have failed at open; this check catches everything else: directories, device nodes, FIFOs, sockets. Message (Chinese): 'read target is not a regular file: {target}'.","triggerScenarios":"Passing a directory path, a named pipe, /dev/null or another device node to the private read helper (the function that takes max_bytes). Happens when a glob or user input yields a non-file path.","commonSituations":"Passing a config/cache path that is actually a directory (e.g. the private dir itself instead of a file inside it); Unix tools creating FIFOs at expected file locations; glob patterns matching sockets in runtime dirs.","solutions":["Check the caller: ensure you pass a file path, not its parent directory","Verify with Path(target).is_file() (or os.path.isfile) before invoking the read helper in your own glue code","If a FIFO/socket sits at the expected file path, remove it and let the app recreate the real file"],"exampleFix":"# before\ndata = read_private_file(\"~/.config/agent-reach\")  # that's the directory\n\n# after\ndata = read_private_file(\"~/.config/agent-reach/credentials.yaml\")","handlingStrategy":"type-guard","validationCode":"import os\n\ndef is_regular_file(path: str) -> bool:\n    try:\n        return os.path.isfile(path)  # True only for regular files (follows no special nodes)\n    except (OSError, ValueError):\n        return False","typeGuard":"import stat, os\n\ndef is_regular_file_strict(path: str) -> bool:\n    \"\"\"True when path exists and is a regular file (not dir/fifo/socket/device).\"\"\"\n    try:\n        return stat.S_ISREG(os.stat(path).st_mode)\n    except OSError:\n        return False","tryCatchPattern":"from agent_reach.utils.paths import PrivatePathError\ntry:\n    payload = read_private(target, max_bytes=cap)\nexcept PrivatePathError as e:\n    if \"常规文件\" in str(e):\n        target = find_real_file(target)  # e.g. append the expected filename\n        payload = read_private(target, max_bytes=cap)\n    else:\n        raise","preventionTips":["Assert is_regular_file() on user- or glob-supplied paths before reading","Log the path (not contents) on failure to spot directory-vs-file mixups fast","In tests, always create real files, never FIFOs/symlinks, under the private dir"],"tags":["filesystem","validation","security","paths"],"backgroundTag":null,"analyzedSha":"93ae1d18c37b707dec053c7c4f9d91cd8ef8943d","analyzedAt":"2026-08-14T22:54:06.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}