{"record":{"id":"937e3d6b564667df","repo":"usestrix/strix","slug":"cannot-read-source-error","errorCode":null,"errorMessage":"Cannot read '{source}': {error}","messagePattern":"Cannot read '(.+?)': (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"strix/interface/utils.py","lineNumber":1734,"sourceCode":"    \"\"\"Validate ``PATH[:DEST]`` specs into source/destination pairs.\n\n    Each spec names a readable host file. ``DEST`` is the path inside\n    ``/workspace``; it defaults to the file name. Raises ``ValueError`` with a\n    user-facing message when a spec is unusable.\n    \"\"\"\n    resolved: list[dict[str, str]] = []\n    seen: dict[str, str] = {}\n    for spec in specs or []:\n        raw, sep, dest = spec.rpartition(\":\")\n        source_text = raw if sep and dest.strip() else spec\n        source = Path(source_text.strip()).expanduser()\n        if not source.is_file():\n            raise ValueError(f\"'{source}' is not an existing file\")\n        try:\n            with source.open(\"rb\"):\n                pass\n        except OSError as error:\n            raise ValueError(f\"Cannot read '{source}': {error}\") from error\n        workspace_rel = _workspace_file_dest(spec, source)\n        if workspace_rel in seen:\n            raise ValueError(\n                f\"Two workspace files target /workspace/{workspace_rel}: \"\n                f\"'{seen[workspace_rel]}' and '{source}'\"\n            )\n        seen[workspace_rel] = str(source)\n        resolved.append(\n            {\n                \"source_path\": str(source.resolve()),\n                \"workspace_path\": f\"/workspace/{workspace_rel}\",\n            }\n        )\n    return resolved\n\n\ndef read_workspace_files(workspace_files: list[dict[str, str]] | None) -> list[dict[str, Any]]:\n    \"\"\"Read resolved workspace files into engine ``extra_files`` entries.\"\"\"","sourceCodeStart":1716,"sourceCodeEnd":1752,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/interface/utils.py#L1716-L1752","documentation":"Raised by resolve_workspace_files() when the source file exists but cannot be opened for reading (an OSError from source.open('rb')). This catches permission problems and races (file deleted or locked between the is_file() check and the open), converting the OSError into a user-facing ValueError.","triggerScenarios":"The source exists but the current user lacks read permission (chmod 000, root-owned file, other user's home), the file sits on an unreadable mount, or it disappears between the is_file() check and the open (TOCTOU race in concurrent scripts).","commonSituations":"Running strix as a different user/sudo context than the file owner; files under /root or another account's home; SELinux/AppArmor denying read; files on an NFS/FUSE mount with restrictive perms; macOS sandboxed terminal denied file access.","solutions":["Check and fix permissions: ls -l FILE and chmod u+r FILE (or chown it back to your user)","Copy the file to a readable location first: sudo cp /root/secret.key /tmp/secret.key && sudo chown $(id -un) /tmp/secret.key, then pass the copy","Verify readability before the run: test -r FILE && strix --workspace-file FILE:secret.key ... || echo 'unreadable'"],"exampleFix":"# before\nstrix --workspace-file /root/secret.key:secret.key -t ./   # permission denied\n# after\nsudo cp /root/secret.key /tmp/secret.key && sudo chown \"$(id -un):\" /tmp/secret.key\nstrix --workspace-file /tmp/secret.key:secret.key -t ./","handlingStrategy":"validation","validationCode":"import os\nfrom pathlib import Path\n\ndef readable(p: str) -> bool:\n    path = Path(p).expanduser()\n    return path.is_file() and os.access(path, os.R_OK)","typeGuard":null,"tryCatchPattern":"try:\n    resolve_workspace_files(specs)\nexcept ValueError as e:\n    if 'Cannot read' in str(e):\n        fix_permissions_or_copy_file()\n    else:\n        raise","preventionTips":["Gate sources with os.access(path, os.R_OK) before the run","Run strix as the user who owns the injected files","Copy privileged files to a user-readable temp location first"],"tags":["strix","cli","permissions","file-io","workspace-files"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}