diff --git a/changelogs/fragments/loop_undefined_delegate_to.yaml b/changelogs/fragments/loop_undefined_delegate_to.yaml
new file mode 100644
index 00000000000..e7e81d2b3d3
--- /dev/null
+++ b/changelogs/fragments/loop_undefined_delegate_to.yaml
@@ -0,0 +1,4 @@
+bugfixes:
+- loop - Ensure that a loop with a when condition that evaluates to false and delegate_to, will short circuit if the
+  loop references an undefined variable. This matches the behavior in the same scenario without delegate_to
+  (https://github.com/ansible/ansible/issues/45189)
diff --git a/lib/ansible/vars/manager.py b/lib/ansible/vars/manager.py
index 921e63d92ac..a88b7ae9961 100644
--- a/lib/ansible/vars/manager.py
+++ b/lib/ansible/vars/manager.py
@@ -512,7 +512,12 @@ class VariableManager:
             else:
                 raise AnsibleError("Failed to find the lookup named '%s' in the available lookup plugins" % task.loop_with)
         elif task.loop is not None:
-            items = templar.template(task.loop)
+            try:
+                items = templar.template(task.loop)
+            except AnsibleUndefinedVariable:
+                # This task will be skipped later due to this, so we just setup
+                # a dummy array for the later code so it doesn't fail
+                items = [None]
         else:
             has_loop = False
             items = [None]
diff --git a/test/integration/targets/loops/tasks/main.yml b/test/integration/targets/loops/tasks/main.yml
index 8b1d635e6e5..1b8a7450504 100644
--- a/test/integration/targets/loops/tasks/main.yml
+++ b/test/integration/targets/loops/tasks/main.yml
@@ -233,3 +233,22 @@
 - assert:
     that:
       - ansible_search_path == loop_search_path.results.0.item
+
+# https://github.com/ansible/ansible/issues/45189
+- name: with_X conditional delegate_to shortcircuit on templating error
+  debug:
+    msg: "loop"
+  when: false
+  delegate_to: localhost
+  with_list: "{{ fake_var }}"
+  register: result
+  failed_when: result is not skipped
+
+- name: loop conditional delegate_to shortcircuit on templating error
+  debug:
+      msg: "loop"
+  when: false
+  delegate_to: localhost
+  loop: "{{ fake_var }}"
+  register: result
+  failed_when: result is not skipped