Repository: keras-team/keras
Issue category: Bug Report

apply_gradients AttributeError: 'ResourceVariable' object has no attribute 'overwrite_with_gradient'
When I have a mix of tf.Variable and KerasVariables I get the following error:
```
--> 632     if v.overwrite_with_gradient:
    633         if self.gradient_accumulation_steps:
    634             # Utilize a stateless manner for JAX compatibility
    635             steps = self.gradient_accumulation_steps

AttributeError: 'ResourceVariable' object has no attribute 'overwrite_with_gradient'
```

I suspect this is because my list of variables is [KerasVariables] + [tf.Variables]
and the following line only checks the first in the list as to whether overwrite_with_gradient can be used?
https://github.com/keras-team/keras/blob/660da946d33ccbb53575f15a17abdfd725cd2086/keras/src/optimizers/base_optimizer.py#L675



Functions to edit:
keras/src/optimizers/base_optimizer.py:BaseOptimizer._overwrite_variables_directly_with_gradients
keras/src/optimizers/base_optimizer.py:BaseOptimizer._filter_empty_gradients

Patch:
diff --git a/keras/src/optimizers/base_optimizer.py b/keras/src/optimizers/base_optimizer.py
index b966c15bc17..8717192fa84 100644
--- a/keras/src/optimizers/base_optimizer.py
+++ b/keras/src/optimizers/base_optimizer.py
@@ -672,7 +672,7 @@ def _overwrite_variables_directly_with_gradients(self, grads, vars):
         """
         # Shortcut for `tf.Variable` because it doesn't have a
         # `overwrite_with_gradient` attr
-        if not hasattr(vars[0], "overwrite_with_gradient"):
+        if any(not hasattr(v, "overwrite_with_gradient") for v in vars):
             return grads, vars
 
         # Shallow copies
@@ -723,7 +723,11 @@ def _filter_empty_gradients(self, grads, vars):
             if filtered_grads[i] is None:
                 filtered_grads.pop(i)
                 v = filtered_vars.pop(i)
-                missing_grad_vars.append(v.path)
+                try:
+                    missing_grad_vars.append(v.path)
+                except AttributeError:
+                    # `tf.Variable` doesn't have `path` attr.
+                    missing_grad_vars.append(v.name)
 
         if not filtered_grads:
             raise ValueError("No gradients provided for any variable.")

Test patch: diff --git a/keras/src/optimizers/optimizer_test.py b/keras/src/optimizers/optimizer_test.py
index 1ac35e63cdd..7d661df9a3c 100644
--- a/keras/src/optimizers/optimizer_test.py
+++ b/keras/src/optimizers/optimizer_test.py
@@ -401,3 +401,25 @@ def test_pickleable_optimizers(self, optimizer):
         reloaded = pickle.loads(pickle.dumps(optimizer))
 
         self.assertEqual(optimizer.get_config(), reloaded.get_config())
+
+    @pytest.mark.skipif(
+        backend.backend() != "tensorflow",
+        reason="The tf.Variable test can only run with TensorFlow backend.",
+    )
+    def test_mixed_with_tf_variables(self):
+        import tensorflow as tf
+
+        v = backend.Variable([[1.0, 2.0], [3.0, 4.0]])
+        grads = backend.convert_to_tensor([[1.0, 1.0], [1.0, 1.0]])
+        tf_v = tf.Variable([[1.0, 2.0], [3.0, 4.0]])
+        tf_grads = backend.convert_to_tensor([[1.0, 1.0], [1.0, 1.0]])
+        optimizer = optimizers.Adam(learning_rate=1.0)
+        optimizer.apply_gradients([(grads, v), (tf_grads, tf_v)])
+        self.assertAllClose(optimizer.iterations, 1)
+
+        # Test with no grads
+        with self.assertWarnsRegex(
+            UserWarning, "Gradients do not exist for variables"
+        ):
+            optimizer.apply_gradients([(grads, v), (None, tf_v)])
+            self.assertAllClose(optimizer.iterations, 2)