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

Ansible Error Guide: 'unable to convert to int' — Fix Argument Type Mismatches

Quick answer

Fix Ansible's 'we were unable to convert to int' argument error by casting templated strings, defaulting empty vars, and matching module argument types.

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

Ansible raises this during argument validation when a module argument declared as an integer receives a value it cannot coerce to one:

fatal: [app01]: FAILED! => {"changed": false, "msg": "argument 'mode' is of type <class 'str'> and we were unable to convert to int: <class 'str'> cannot be converted to an int"}

A common templated variant looks like this, where a variable resolved to something non-numeric:

fatal: [app01]: FAILED! => {"changed": false, "msg": "argument 'port' is of type <class 'str'> and we were unable to convert to int: invalid literal for int() with base 10: ''"}

The module never executed. Ansible type-checks arguments first, and a value that cannot become the declared type stops the task before any change is made.

Symptoms

  • A task fails with is of type <class 'str'> and we were unable to convert to int.
  • The failure references an empty string (''), meaning a variable resolved to nothing.
  • A value that “looks like a number” fails because it is a string with a stray character or whitespace.
  • The same task works when the value is hard-coded but fails when templated from a variable.
  • A mode/port/timeout/retries argument is the one named in the message.

Common Root Causes

  • Undefined or empty variableport: "{{ svc_port }}" where svc_port is unset, resolving to ''.
  • String that is not purely numeric — a value like "8080 " with whitespace, "8_080", or "eight".
  • Wrong source type — a value read from JSON/CSV/register stdout that carries quotes or newlines.
  • Missing | int filter — a templated numeric string that the module expects already cast.
  • Octal confusion on mode — passing file mode as an unquoted or malformed value the module cannot interpret.
  • Boolean where int expected — YAML coercing a value to True/False.

Diagnostic Workflow

Print the resolved value and its type before the failing task so you can see what the module actually receives:

- name: Inspect the value being passed
  ansible.builtin.debug:
    msg: "port=>>{{ svc_port | default('UNDEFINED') }}<< type={{ svc_port | type_debug }}"

- name: Start the app with a numeric port
  ansible.builtin.command:
    cmd: "start-app --port {{ svc_port | int }}"   # cast the string to int explicitly

Run the play with verbosity to see the constructed argument dictionary:

ansible-playbook -i inventory app.yml --limit app01 -vvv

Confirm the module’s expected argument type in the docs:

ansible-doc ansible.builtin.wait_for | grep -A4 -i 'port\|timeout'

Reproduce with a deliberately non-numeric value to validate the cast fixes it:

ansible app01 -i inventory -m wait_for -a "port='' timeout=30"
# msg: ... unable to convert to int: invalid literal for int() with base 10: ''

Example Root Cause Analysis

A deploy play failed intermittently with argument 'port' ... unable to convert to int: invalid literal for int() with base 10: ''. It only failed for a subset of hosts. Adding a debug with type_debug showed svc_port resolving to an empty string on exactly those hosts: the variable was defined in a host_vars file that existed for most hosts but was missing for the failing ones, so svc_port fell through to undefined and templated to ''.

The fix had two parts. First, svc_port: "{{ svc_port | default(8080) | int }}" gave a sane default and an explicit cast so a missing value no longer produced an empty string. Second, an assert at the top of the play validated that svc_port was defined and numeric, turning a mid-play type error into a clear pre-flight failure. The empty-string case is the tell here: it almost always means an undefined variable, not a genuinely non-numeric value.

Prevention Best Practices

  • Apply | int (or | float) explicitly to templated numeric values so the module receives the type it declares.
  • Provide | default(<n>) for optional numeric variables so an unset value becomes a number, not an empty string.
  • Add an assert early in the play validating that required numeric vars are defined and match ^[0-9]+$.
  • Use type_debug in a temporary debug task to see the real type when a conversion fails.
  • Quote file mode values consistently and pass them in the form the module documents.

Quick Command Reference

# Show the resolved value and its type
- debug: msg="{{ myvar | default('UNDEF') }} :: {{ myvar | type_debug }}"

# Run with the argument dict visible
ansible-playbook -i inventory play.yml --limit <host> -vvv

# Check a module argument's expected type
ansible-doc <module> | grep -A4 -i <argument>

# Reproduce the conversion failure
ansible <host> -i inv -m wait_for -a "port='' timeout=30"

Conclusion

“unable to convert to int” is a type-check failure, not a logic bug: a module argument declared as an integer got a value it could not coerce. When the message shows an empty string, suspect an undefined variable first. Cast templated numerics with | int, default optional ones, and assert required vars up front so a type mismatch fails loudly at pre-flight instead of deep inside a run. Match the value to the argument’s declared type and the task proceeds.

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.