# ansible 2.21 compatibility issues for paramiko

**URL:** <https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330>\
**Category:** Guides, FAQs & Howtos\
**Tags:** howto\
**Created:** [September 20, 2026, 7:46pm UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330 "2026-09-20T19:46:32Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sumitguptaibm](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sumitguptaibm/32/11237_2.png) [@sumitguptaibm](https://forum.ansible.com/u/sumitguptaibm)\
**Post date:** [September 20, 2026, 7:46pm UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330/1 "2026-09-20T19:46:33Z")

</div>

Hi,

I’m maintaining an Ansible collection that currently supports multiple ansible-core versions.

Our module utility currently imports Paramiko as:

```python
from ansible.module_utils.compat.paramiko import paramiko

```

This works with ansible-core 2.20 and earlier, but with ansible-core 2.21 we get:

```plaintext
ModuleNotFoundError: No module named 'ansible.module_utils.compat.paramiko'

```

I understand that `ansible.module_utils.compat.paramiko` was removed in ansible-core 2.21, and the recommended approach for 2.21+ is:

```python
import paramiko

```

Our collection already has Paramiko listed in `requirements.txt`:

```plaintext
cryptography
paramiko
pexpect

```

My question is:

**What is the recommended way for an Ansible collection to support both ansible-core 2.20 and earlier, as well as 2.21 and later?**

Would the recommended implementation simply be:

```python
import paramiko

```

and make Paramiko an explicit dependency of the collection?

Or should the collection use a compatibility pattern such as:

```python
try:
    import paramiko
except ImportError:
    from ansible.module_utils.compat.paramiko import paramiko

```

The goal is to maintain a single codebase that works across the supported ansible-core versions without depending on an Ansible internal/removed module.

I also tested this with:

```bash
ansible-test sanity --test import --python 3.12

```

After changing to:

```python
import paramiko

```

the error changed to:

```plaintext
ModuleNotFoundError: No module named 'paramiko'

```

even though Paramiko is installed in my development virtual environment:

```plaintext
paramiko==5.0.0

```

So I would also appreciate clarification on the recommended way to make a collection’s external Python dependency available to the `ansible-test sanity import` environment.

Thanks!

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [September 20, 2026, 7:50pm UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330/2 "2026-09-20T19:50:48Z")

</div>

> [@sumitguptaibm](#):
>
> Or should the collection use a compatibility pattern such as:
> 
> ```auto
> try:
> import paramiko
> except ImportError:
> from ansible.module_utils.compat.paramiko import paramiko
> 
> ```
> 
> The goal is to maintain a single codebase that works across the supported ansible-core versions without depending on an Ansible internal/removed module.

That’s the common way to handle such situations (you should wrap `import paramiko` in `try: ... except ImportError:` though, that’s what the module utils did as well). The paramiko wrapper in ansible.module\_utils.compat didn’t do much anything, except disabling some warnings: [ansible/lib/ansible/module\_utils/compat/paramiko.py at stable-2.20 · ansible/ansible · GitHub](https://github.com/ansible/ansible/blob/stable-2.20/lib/ansible/module_utils/compat/paramiko.py)

I would probably remove the import for `ansible.module_utils.compat.paramiko` completely and copy the suppression rules to your collection, so you have a single way how paramiko is imported.

---

<div class="post-metadata">

**Author:** ![sumitguptaibm](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sumitguptaibm/32/11237_2.png) [@sumitguptaibm](https://forum.ansible.com/u/sumitguptaibm)\
**Post date:** [September 21, 2026, 5:35am UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330/3 "2026-09-21T05:35:25Z")

</div>

> [@felixfontein](#):
>
> I would probably remove the import for `ansible.module_utils.compat.paramiko` completely and copy the suppression rules to your collection, so you have a single way how paramiko is imported.

When you say “_copy the suppression rules to your collection_”, could you point me to the specific Ansible suppression rule/configuration you’re referring to, and where it should be placed in the collection? How would it then work for ansible 2.20 and lower (many customers may be on that level).

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [September 21, 2026, 1:45pm UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330/4 "2026-09-21T13:45:42Z")

</div>

The warnings that are suppressed are described here [ansible/lib/ansible/module\_utils/compat/paramiko.py at stable-2.20 · ansible/ansible · GitHub](https://github.com/ansible/ansible/blob/stable-2.20/lib/ansible/module_utils/compat/paramiko.py#L13-L27).

> **So you could replace that import in a backwards compatible way with something like this:**
>
> ```python
> import warnings
> 
> PARAMIKO_IMPORT_ERR = None
> 
> try:
> with warnings.catch_warnings():
> # Blowfish has been moved, but the deprecated import is used by paramiko versions older than 2.9.5.
> # See: https://github.com/paramiko/paramiko/pull/2039
> warnings.filterwarnings('ignore', message='Blowfish has been ', category=UserWarning)
> # TripleDES has been moved, but the deprecated import is used by paramiko versions older than 3.3.2 and 3.4.1.
> # See: https://github.com/paramiko/paramiko/pull/2421
> warnings.filterwarnings('ignore', message='TripleDES has been ', category=UserWarning)
> import paramiko 
> # paramiko and gssapi are incompatible and raise AttributeError not ImportError
> # When running in FIPS mode, cryptography raises InternalError
> # https://bugzilla.redhat.com/show_bug.cgi?id=1778939
> except Exception as err:
> paramiko = None # type: ignore[no-redef]
> PARAMIKO_IMPORT_ERR = err
> 
> ```

---

<div class="post-metadata">

**Author:** ![sumitguptaibm](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sumitguptaibm/32/11237_2.png) [@sumitguptaibm](https://forum.ansible.com/u/sumitguptaibm)\
**Post date:** [September 22, 2026, 4:52am UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330/5 "2026-09-22T04:52:35Z")

</div>

The issue here is not only about errors. Sanity error got resolved, but paramiko is not imported.  
PARAMIKO\_IMPORT\_ERR = None

```auto
PARAMIKO_IMPORT_ERR = None

try:
    with warnings.catch_warnings():
        # Blowfish has been moved, but the deprecated import is used by paramiko versions older than 2.9.5.
        # See: https://github.com/paramiko/paramiko/pull/2039
        warnings.filterwarnings('ignore', message='Blowfish has been ', category=UserWarning)
        # TripleDES has been moved, but the deprecated import is used by paramiko versions older than 3.3.2 and 3.4.1.
        # See: https://github.com/paramiko/paramiko/pull/2421
        warnings.filterwarnings('ignore', message='TripleDES has been ', category=UserWarning)
        import paramiko 
# paramiko and gssapi are incompatible and raise AttributeError not ImportError
# When running in FIPS mode, cryptography raises InternalError
# https://bugzilla.redhat.com/show_bug.cgi?id=1778939
except Exception as err:
    paramiko = None
    PARAMIKO_IMPORT_ERR = err

if paramiko is None:
    print(f"Paramiko was not imported: {PARAMIKO_IMPORT_ERR}")
else:
    print(f"Paramiko imported successfully: {paramiko. __version__ }")

```

```auto
% ansible --version
ansible [core 2.19.13]

```

```auto
% python --version
Python 3.13.5

```

```auto
% python -c "import paramiko; print(paramiko. __version__ )"
5.0.0

```

```auto
% ansible-test sanity --test import plugins/module_utils/ibm_svc_ssh.py         
Running sanity test "import" on Python 3.8
Running sanity test "import" on Python 3.9
WARNING: Skipping sanity test "import" on Python 3.10 because it could not be found.
WARNING: Skipping sanity test "import" on Python 3.11 because it could not be found.
Running sanity test "import" on Python 3.12
ERROR: Found 1 import issue(s) on python 3.12 which need to be resolved:
ERROR: plugins/module_utils/ibm_svc_ssh.py:0:0: stdout: Paramiko was not imported: No module named 'paramiko'
See documentation for help: https://docs.ansible.com/ansible-core/2.19/dev_guide/testing/sanity/import.html
Running sanity test "import" on Python 3.13
ERROR: Found 1 import issue(s) on python 3.13 which need to be resolved:
ERROR: plugins/module_utils/ibm_svc_ssh.py:0:0: stdout: Paramiko was not imported: No module named 'paramiko'
See documentation for help: https://docs.ansible.com/ansible-core/2.19/dev_guide/testing/sanity/import.html
FATAL: The 2 sanity test(s) listed below (out of 6) failed. See error output above for details.
import --python 3.12
import --python 3.13

```

Is it recommended to reinstall a new env to test it?

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [September 22, 2026, 12:58pm UTC](https://forum.ansible.com/t/ansible-2-21-compatibility-issues-for-paramiko/46330/6 "2026-09-22T12:58:24Z")

</div>

Third-party imports are **never** available in sanity tests (and you can’t change that). Your code has to work in sanity tests without them being around.

In case you haven’t read it yet: [import — Ansible Community Documentation](https://docs.ansible.com/projects/ansible/devel/dev_guide/testing/sanity/import.html#handling-import-errors)
