{"record":{"id":"ba90749119e690f0","repo":"ansible/ansible","slug":"unable-to-read-the-contents-of-path-r","errorCode":null,"errorMessage":"Unable to read the contents of {path!r}.","messagePattern":"Unable to read the contents of (.+?)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"lib/ansible/modules/replace.py","lineNumber":260,"sourceCode":"    res_args = dict(rc=0)\n    contents = None\n\n    params['after'] = to_text(params['after'], errors='surrogate_or_strict', nonstring='passthru')\n    params['before'] = to_text(params['before'], errors='surrogate_or_strict', nonstring='passthru')\n    params['regexp'] = to_text(params['regexp'], errors='surrogate_or_strict', nonstring='passthru')\n    params['replace'] = to_text(params['replace'], errors='surrogate_or_strict', nonstring='passthru')\n\n    if os.path.isdir(path):\n        module.fail_json(rc=256, msg='Path %s is a directory !' % path)\n\n    if not os.path.exists(path):\n        module.fail_json(rc=257, msg='Path %s does not exist !' % path)\n    else:\n        try:\n            with open(path, 'r', encoding=encoding) as f:\n                contents = f.read()\n        except OSError as ex:\n            raise Exception(f\"Unable to read the contents of {path!r}.\") from ex\n\n    pattern = u''\n    if params['after'] and params['before']:\n        pattern = u'%s(?P<subsection>.*?)%s' % (params['after'], params['before'])\n    elif params['after']:\n        pattern = u'%s(?P<subsection>.*)' % params['after']\n    elif params['before']:\n        pattern = u'(?P<subsection>.*)%s' % params['before']\n\n    if pattern:\n        section_re = re.compile(pattern, re.DOTALL)\n        match = re.search(section_re, contents)\n        if match:\n            section = match.group('subsection')\n            indices = [match.start('subsection'), match.end('subsection')]\n        else:\n            res_args['msg'] = 'Pattern for before/after params did not match the given file: %s' % pattern\n            res_args['changed'] = False","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/ansible/ansible/blob/9cf16a4aca7898481c257f1e17ad28d0b67b1f85/lib/ansible/modules/replace.py#L242-L278","documentation":"The replace module raises this Exception after its own directory/exists pre-checks pass but open(path).read() still fails with OSError. Since existence was just verified, the realistic causes are permission denied, a race where the file vanished, or a read error (I/O error, SELinux denial).","triggerScenarios":"replace on a file the module user cannot read (root-owned 0600 without become), a symlink loop, or the file being deleted between the exists check and the read.","commonSituations":"Editing /etc files while connecting as a non-root user without become: true; SELinux confining the ansible SSH session; path is a dangling symlink that exists but open fails.","solutions":["Confirm the user can read the file: run cat on it as that user from the host","Add become: true for privileged files","Check for symlink oddities (ls -l path) and target the real file","Look for SELinux denials (ausearch -m avc) if DAC looks fine"],"exampleFix":"# before\n- ansible.builtin.replace:\n    path: /etc/nginx/nginx.conf\n    regexp: 'listen 80'\n    replace: 'listen 8080'\n\n# after\n- name: same edit with privilege\n  become: true\n  ansible.builtin.replace:\n    path: /etc/nginx/nginx.conf\n    regexp: 'listen 80'\n    replace: 'listen 8080'","handlingStrategy":"validation","validationCode":"import os\n\ndef replace_target_readable(path):\n    return os.path.isfile(path) and os.access(path, os.R_OK)","typeGuard":null,"tryCatchPattern":"try:\n    with open(path, 'r', encoding=encoding) as f:\n        contents = f.read()\nexcept OSError as ex:\n    raise Exception(f'Unable to read the contents of {path!r}.') from ex","preventionTips":["Use become for privileged config files","Verify readability as the connection user before editing","Avoid racing concurrent deletions of the target file"],"tags":["replace","filesystem","permissions","ansible-module"],"backgroundTag":null,"analyzedSha":"9cf16a4aca7898481c257f1e17ad28d0b67b1f85","analyzedAt":"2026-08-15T00:15:47.100Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}