Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Ansible By James Joyner IV · · 9 min read

Ansible Error Guide: 'Failed to set permissions on the temporary files' — Fix Unprivileged become

Quick answer

Fix Ansible's 'Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user' by installing ACL support or adjusting become and the temp dir.

Part of the Ansible Playbook & Module Errors hub
  • #ansible
  • #automation
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

This failure appears the moment a task uses become: true with a become_user that is not root and not the connecting user. Ansible writes its module payload to a temporary directory as the login user, then hands off to the unprivileged become_user, and that second user cannot read the files:

fatal: [web01]: FAILED! => {"changed": false, "msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chmod: invalid mode: 'A+user:deploy:rx:allow'\nTry 'chmod --help' for more information.\n}). For information on working around this, see https://docs.ansible.com/ansible-core/devel/playbook_guide/playbooks_privilege_escalation.html#risks-of-becoming-an-unprivileged-user"}

The root of the message is always the same: Ansible tried to grant the target become_user access to its temp files, the preferred mechanism (POSIX ACLs via setfacl) was unavailable, and the fallback failed. The user-facing symptom is that any become_user: someappuser task dies before the actual module ever runs.

Symptoms

  • Tasks with become: true and a non-root become_user fail; the same tasks run fine with become_user: root (the default).
  • The error names “becoming an unprivileged user” and often references setfacl, chmod, or chown in the err field.
  • remote_tmp (default ~/.ansible/tmp) is on a filesystem mounted noacl, or the acl package is not installed.
  • Connecting as an unprivileged login user and then become-ing to a different unprivileged user (the classic unprivileged-to-unprivileged hop).
  • Works on one host, fails on another whose /tmp or home filesystem lacks ACL support.

Common Root Causes

  • ACL tools missing: the acl package (providing setfacl/getfacl) is not installed on the target, so Ansible cannot grant the become_user read/execute on its temp dir.
  • Filesystem mounted without ACL support: the partition holding remote_tmp is mounted noacl, or is a filesystem type that doesn’t support POSIX ACLs, so setfacl fails even when installed.
  • Unprivileged-to-unprivileged become: you connect as deploy and become_user: appuser. Neither is root, so Ansible must widen permissions on the temp files — exactly the case that needs ACLs.
  • allow_world_readable_tmpfiles misunderstanding: teams flip this expecting a fix, but it only helps when the content isn’t sensitive and world-readable temp files are acceptable.
  • remote_tmp pointing at a restrictive path: a custom remote_tmp under a directory the become_user can’t traverse.

Diagnostic Workflow

First confirm it is specifically the unprivileged-become path by re-running the single task with maximum verbosity:

ansible-playbook site.yml --limit web01 --tags deploy -vvv

Look in the -vvv output for the temp dir path (ANSIBLE_REMOTE_TEMP / ~/.ansible/tmp/ansible-tmp-...) and the exact err — it tells you whether setfacl was missing or the mount rejected it.

Check whether ACL tooling exists on the target and whether the temp filesystem supports it:

ansible web01 -m raw -a 'which setfacl; rpm -q acl 2>/dev/null || dpkg -l acl 2>/dev/null | tail -1'
ansible web01 -m raw -a 'df -P ~/.ansible/tmp | tail -1; mount | grep -E "$(df -P ~/.ansible/tmp | tail -1 | awk "{print \$1}")"'

Reproduce the minimal failing case to isolate it from the rest of the play:

- name: Reproduce unprivileged become
  hosts: web01
  become: true
  become_user: appuser
  tasks:
    - name: Trivial command as unprivileged user
      ansible.builtin.command: id

Verify the fix candidate — installing acl — resolves it:

- name: Ensure ACL support then test become
  hosts: web01
  tasks:
    - name: Install acl package
      become: true
      ansible.builtin.package:
        name: acl
        state: present

    - name: Now try the unprivileged become
      become: true
      become_user: appuser
      ansible.builtin.command: id

Example Root Cause Analysis

A deploy playbook connected as deploy and used become: true with become_user: appuser to run application steps as the service account. It passed on older hosts and failed on a freshly provisioned minimal image with the ACL error citing setfacl: command not found.

The -vvv output showed Ansible trying to setfacl -m u:appuser:r-x on ~/.ansible/tmp/ansible-tmp-... and getting “command not found”. The minimal image shipped without the acl package, and the older hosts happened to have it pulled in as a dependency of another tool. Because both the login user (deploy) and the target (appuser) were unprivileged, Ansible could not simply chown the temp files as root — it needed ACLs, which weren’t there.

The fix was a pre_tasks block that installs acl with become: true (escalating to root, where no ACL is needed) before any unprivileged-become task runs. After that, the become_user: appuser tasks succeeded on every host. The team added acl to their base image build so new hosts never hit it again.

Prevention Best Practices

  • Bake acl into your base image or install it in an early become: true (to root) task, before any become_user targets a non-root account.
  • Prefer becoming root when the task doesn’t strictly need to run as a specific service user — root-to-anything doesn’t need ACLs.
  • Keep remote_tmp on an ACL-capable filesystem; avoid pointing it at partitions mounted noacl or at exotic filesystem types.
  • Set remote_tmp under the become_user’s own home when appropriate, so the target user already owns the path.
  • Only use allow_world_readable_tmpfiles = true as a deliberate, documented choice when the transferred content is not sensitive — it makes temp files world-readable.
  • Test the unprivileged-become path in CI/Molecule on a minimal image so a missing acl package is caught before production.

Quick Command Reference

# Re-run the failing task with full verbosity to see the real err
ansible-playbook site.yml --limit web01 -vvv

# Check for setfacl and the acl package on the target
ansible web01 -m raw -a 'which setfacl; dpkg -l acl 2>/dev/null | tail -1 || rpm -q acl'

# Install acl fleet-wide (escalates to root, which needs no ACL)
ansible all -b -m package -a 'name=acl state=present'

# Inspect the temp filesystem's mount options for noacl
ansible web01 -m raw -a 'mount | grep -Ei "acl|/tmp|home"'

# Confirm the fix with a trivial unprivileged-become command
ansible web01 -b --become-user appuser -m command -a id

Conclusion

“Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user” is almost always the unprivileged-to-unprivileged become path meeting a host without POSIX ACL support. Read the err field in -vvv to confirm whether setfacl is missing or the mount rejects ACLs, install the acl package (ideally in your base image), and prefer becoming root when a specific service user isn’t required. Once ACL support is present on the temp filesystem, become_user to a non-root account works cleanly.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.