Issue with ansible to access lxd container

I have ansible on the same lxd server, the purpose is I want ansible to manage containers
so I created container
and a dynamic inventory (so that I don have to type the name of container each time)
so here is the dynamic inventory

plugin: community.general.lxd
url: unix:/var/snap/lxd/common/lxd/unix.socket
state: RUNNING

here is the output of the inventory

ansible-inventory -i lxd.yaml --graph
  |  |--nginx-1

I ran ansible -i lxd.yaml -m ping all
and got this output

nginx-1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: root@container-ip: Permission denied (publickey).",
    "unreachable": true

then I have this inventory

all :
  vars : 
    ansible_connection : lxd 
    ansible_user : root 
    ansible_become : no 
  children : 
    local : 
      vars : 
        ansible_lxd_remote : local 
        ansible_lxd_project : default
      hosts :


ansible -i hosts.yaml -m ping all
nginx-1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    "changed": false,
    "ping": "pong"

so my guess is in the dynamic inventory use ssh to access the container but failed on the second part I specify to use ansible_connection=lxd so ansible was able to access the container
is there any way to make ansible use lxd connection on the dynamic inventory

There seems to be an issue with ansible-inventory as it reports the ansible_connection as ssh for all running instances (and local for those stopped). You can see it with ansible-inventory -i lxd.yml --list:

    "_meta": {
        "hostvars": {
            "c1": {
                "ansible_connection": "ssh",
                "ansible_host": "",
                "ansible_lxd_os": "ubuntu",
                "ansible_lxd_profile": [
                "ansible_lxd_project": "default",
                "ansible_lxd_release": "noble",
                "ansible_lxd_state": "running",
                "ansible_lxd_type": "container"
            "j1": {
                "ansible_connection": "local",
                "ansible_lxd_os": "ubuntu",
                "ansible_lxd_profile": [
                "ansible_lxd_project": "default",
                "ansible_lxd_release": "noble",
                "ansible_lxd_state": "stopped",
                "ansible_lxd_type": "container"
    "all": {
        "children": [
    "ungrouped": {
        "hosts": [

FYI, my lxd.yml file:

# Usage: ansible-inventory -i lxd.yml --list
plugin: community.general.lxd
url: unix:/var/snap/lxd/common/lxd/unix.socket

That said, if you are OK with a static inventory, it works well:


$ cat ansible.cfg
inventory = hosts.yml
timeout = 30
forks = 10
# avoids creating multiple sessions with systemd-logind
pipelining = True

enable_plugins = yaml, community.general.lxd


    ansible_connection: lxd
    ansible_lxd_project: default
    ansible_lxd_remote: local
    ansible_user: root
    ansible_become: false


- name: ping test
  hosts: all
    - name: test connectivity
$ ansible-playbook books/ping.yml 

PLAY [ping test] *******************************************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************************************************************************************************************************
[WARNING]: Unhandled error in Python interpreter discovery for host j1: instance not running: j1
fatal: [j1]: UNREACHABLE! => {"changed": false, "msg": "instance not running: j1", "unreachable": true}
ok: [c1]

TASK [test connectivity] ***********************************************************************************************************************************************************************************************************************************************************
ok: [c1]

PLAY RECAP *************************************************************************************************************************************************************************************************************************************************************************
c1                         : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
j1                         : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0