
Ansible ZeroDivisionError
- 4 minsFixing Ansible’s ZeroDivisionError When Slicing Docker Image Tags
When automating Docker image management with Ansible, especially syncing images from Docker Hub to a private Harbor registry, it’s common to sync images between the two. I decided to change my approach from a python script to an ansible playbook for ease of use and easier maintenance with future development. However, sometimes a solution that should be straightforward can spiral into cryptic errors — like this classic head-scratcher:
ZeroDivisionError: integer division or modulo by zero
Lemme break down what causes this, how to fix it, and a few best practices for working with JSON and Jinja filters in Ansible.
The Setup
I’m using the Docker Hub API to get a list of tags from dockerhub:
uri:
url: "https://registry.hub.docker.com/v2/repositories/library/nginx/tags?page_size=100"
return_content: yes
register: docker_tag_results
Then I parse and store only the latest 5 tags per image:
```yaml
set_fact:
docker_image_tags: >-
{{
docker_image_tags | default({}) |
combine({
item.item: (
(item.content | from_json).results | default([]) |
map(attribute='name') | select('string') | list
)[0:5]
})
}}
From here it looks clean if you run a debug task and print the item.content. However….
The Problem: Jinja’s slice
is NOT Python’s slice
In Python, slice(0, 5)
would mean: get items from index 0
to 4
.
But in Jinja/Ansible, the slice
filter is used for chunking lists, like this:
['a', 'b', 'c', 'd', 'e', 'f'] | slice(3)
# → [['a', 'b', 'c'], ['d', 'e', 'f']]
So when you do slice(0, 5)
, Jinja tries to split the list into 0 groups of 5, triggering the error:
ZeroDivisionError: integer division or modulo by zero
It’s not a slicing operation — it’s a grouping operation.
A Good Solution: Using [0:5]
Instead of using the slice
filter, you can just use Python-style list slicing directly:
```yaml
set_fact:
docker_image_tags: >-
{{
docker_image_tags | default({}) |
combine({
item.item: (
(item.content | from_json).results | default([]) |
map(attribute='name') | select('string') | list
)[0:5]
})
}}
This gives you what you want the first 5 tag names without triggering any errors.
Future Foundation: Avoiding Future Issues
Here are some best practices I found that should be consider in Ansible/Jinja workflows to help prevent future hiccups like this:
1. Use default([])
often
Always apply default([])
when accessing JSON objects like .results
to guard against nulls or missing keys.
2. Use select('string')
Some APIs return null values in tag arrays. Filtering with select('string')
ensures you don’t pass None
into downstream logic.
3. Validate with a fail task
Don’t just assume the tag list exists. Instead, explicitly throw a failure condition when it doesn’t:
- name: Fail if image tag list is empty
fail:
msg: "Image returned no valid tags."
when: item.value | length == 0
loop: ""
In Conclusion
The ZeroDivisionError
in Ansible might seem mysterious, but it really comes down to Jinja filters acting differently than expected in Ansible. If you’re using slice()
thinking it works like Python — it doesn’t. The fix here is to use [0:5]
for slicing tags.
TIP: Always code defensively when dealing with JSON data from external APIs.
Security Warning
This is a solution to syncing docker and harbor images but requires saving credentials in plain text. The ansible playbook shared here as an example
Consider using GITHUB SECRETS or ANSIBLE VALUT to encrypt secrets when using this in production.