ansible/ansible · error · ValueError

MD5 not available. Possibly running in FIPS mode

Error message

MD5 not available.  Possibly running in FIPS mode

What it means

Raised by AnsibleModule.md5() in ansible.module_utils.basic when the 'md5' hash algorithm is absent from AVAILABLE_HASH_ALGORITHMS. This almost always means the managed host's Python/OpenSSL is running in FIPS-140-2 mode, where OpenSSL refuses to register MD5. The method's own docstring states it will not work on FIPS-compliant systems and that most callers should use sha256/sha1 instead.

Source

Thrown at lib/ansible/module_utils/basic.py:1585

        while block:
            digest_method.update(block)
            block = infile.read(blocksize)
        infile.close()
        return digest_method.hexdigest()

    def md5(self, filename):
        """ Return MD5 hex digest of local file using digest_from_file().

        Do not use this function unless you have no other choice for:
            1) Optional backwards compatibility
            2) Compatibility with a third party protocol

        This function will not work on systems complying with FIPS-140-2.

        Most uses of this function can use the module.sha1 function instead.
        """
        if 'md5' not in AVAILABLE_HASH_ALGORITHMS:
            raise ValueError('MD5 not available.  Possibly running in FIPS mode')
        return self.digest_from_file(filename, 'md5')

    def sha1(self, filename):
        """ Return SHA1 hex digest of local file using digest_from_file(). """
        return self.digest_from_file(filename, 'sha1')

    def sha256(self, filename):
        """ Return SHA-256 hex digest of local file using digest_from_file(). """
        return self.digest_from_file(filename, 'sha256')

    def backup_local(self, fn):
        """make a date-marked backup of the specified file, return True or False on success or failure"""

        backupdest = ''
        if os.path.exists(fn):
            # backups named basename.PID.YYYY-MM-DD@HH:MM:SS~
            ext = time.strftime("%Y-%m-%d@%H:%M:%S~", time.localtime(time.time()))
            backupdest = '%s.%s.%s' % (fn, os.getpid(), ext)

View on GitHub (pinned to 9cf16a4aca)

Solutions

  1. Switch to module.sha256(filename) or module.checksum_s('sha256') for local file digests
  2. For copy/get_url style tasks, pass checksum with a stronger algorithm, e.g. checksum: sha256:...
  3. If a third-party protocol mandates MD5, run the task with FIPS disabled (remove fips=1 and reboot) or use a Python/OpenSSL build with a non-FIPS MD5
  4. If you maintain the module, gate the MD5 path: offer an algorithm option and fall back to sha256 when 'md5' not in AVAILABLE_HASH_ALGORITHMS

Example fix

# before
checksum = module.md5(dest_file)

# after
if 'md5' in AVAILABLE_HASH_ALGORITHMS:
    checksum = module.md5(dest_file)
else:
    checksum = module.sha256(dest_file)
Defensive patterns

Strategy: validation

Validate before calling

from ansible.module_utils.basic import AVAILABLE_HASH_ALGORITHMS

if 'md5' not in AVAILABLE_HASH_ALGORITHMS:
    # FIPS host: pick a strong digest before calling module.md5
    digest = module.sha256(path)
else:
    digest = module.md5(path)

Type guard

def md5_available() -> bool:
    return 'md5' in AVAILABLE_HASH_ALGORITHMS

Try / catch

try:
    digest = module.md5(path)
except ValueError as e:
    if 'FIPS' in str(e):
        digest = module.sha256(path)
    else:
        raise

Prevention

When it happens

Trigger: Calling module.md5('/path/to/file') (directly or via a module feature that compares MD5 checksums, e.g. copy/get_url with checksum=md5:...) on a host where hashlib does not expose md5 because FIPS enforcement (OPENSSL_FORCEFIPS_MODE=1, a FIPS kernel, or a FIPS-configured OpenSSL) is active.

Common situations: RHEL/CentOS hosts in FIPS mode (fips=1 kernel cmdline), government or compliance-hardened environments, and modules that still default to MD5 for backward compatibility with third-party protocols that require MD5.

Related errors


AI-assisted analysis of ansible/ansible@9cf16a4aca (2026-08-15). Data as JSON: /api/errors/5c63e7fde8d6a9d5. Report an issue: GitHub.