Skip to content
DevOps AI ToolKit
All guides
AI for Ansible By James Joyner IV · · 8 min read Last reviewed Jul 2026

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.

  • #ansible
  • #automation
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this Ansible error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

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

Fixed it? Get 500 Ansible & 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.

Stuck on this? Start guided troubleshooting

Open an interactive diagnostic session with this error already loaded. Work a step-by-step plan, record what each check returns, land on a root cause, and export a clean incident summary — no account needed to start.

Did this fix your issue?

Solved it a different way?

Share the fix that worked for you — reviewed, then published to help the next engineer.

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.