diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2c035ee1c..2dd56e16c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
  
 * PayPal
   * Fix bug to ensure that `PayPalVaultRequest.userAuthenticationEmail` is not sent as an empty string
+* ThreeDSecure
+  * Return error if no `dfReferenceId` is returned in the 3D Secure flow
   
 ## 5.3.0 (2024-12-11)
 
diff --git a/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt b/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt
index 121487ecf4..f84437bb5d 100644
--- a/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt
+++ b/ThreeDSecure/src/main/java/com/braintreepayments/api/threedsecure/ThreeDSecureClient.kt
@@ -204,11 +204,17 @@ class ThreeDSecureClient internal constructor(
                     configuration,
                     request
                 ) { consumerSessionId: String?, _ ->
-                    if (consumerSessionId != null) {
-                        try {
+                    if (!consumerSessionId.isNullOrEmpty()) {
                             lookupJSON.put("dfReferenceId", consumerSessionId)
-                        } catch (ignored: JSONException) {
-                        }
+                    } else {
+                        callbackPrepareLookupFailure(
+                            callback,
+                            ThreeDSecurePrepareLookupResult.Failure(
+                                BraintreeException("There was an error retrieving the dfReferenceId.")
+                            )
+                        )
+
+                        return@initialize
                     }
                     braintreeClient.sendAnalyticsEvent(ThreeDSecureAnalytics.LOOKUP_SUCCEEDED)
                     callback.onPrepareLookupResult(
diff --git a/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java b/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java
index 8db8436e20..8377b5adcd 100644
--- a/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java
+++ b/ThreeDSecure/src/test/java/com/braintreepayments/api/threedsecure/ThreeDSecureClientUnitTest.java
@@ -128,10 +128,9 @@ public void prepareLookup_returnsValidLookupJSONString()
     }
 
     @Test
-    public void prepareLookup_returnsValidLookupJSONString_whenCardinalSetupFails()
-        throws JSONException, BraintreeException {
+    public void prepareLookup_initializesCardinal() throws BraintreeException {
         CardinalClient cardinalClient = new MockCardinalClientBuilder()
-            .error(new Exception("cardinal error"))
+            .successReferenceId("fake-df")
             .build();
 
         BraintreeClient braintreeClient = new MockBraintreeClientBuilder()
@@ -148,32 +147,16 @@ public void prepareLookup_returnsValidLookupJSONString_whenCardinalSetupFails()
         ThreeDSecurePrepareLookupCallback callback = mock(ThreeDSecurePrepareLookupCallback.class);
         sut.prepareLookup(activity, basicRequest, callback);
 
-        ArgumentCaptor<ThreeDSecurePrepareLookupResult> captor = ArgumentCaptor.forClass(ThreeDSecurePrepareLookupResult.class);
-        verify(callback).onPrepareLookupResult(captor.capture());
-
-        ThreeDSecurePrepareLookupResult prepareLookupResult = captor.getValue();
-        assertTrue(prepareLookupResult instanceof ThreeDSecurePrepareLookupResult.Success);
-        assertSame(basicRequest, ((ThreeDSecurePrepareLookupResult.Success) prepareLookupResult).getRequest());
-
-        String clientData = ((ThreeDSecurePrepareLookupResult.Success) prepareLookupResult).getClientData();
-        JSONObject lookup = new JSONObject(clientData);
-        Assert.assertEquals("encoded_auth_fingerprint",
-            lookup.getString("authorizationFingerprint"));
-        Assert.assertEquals(lookup.getString("braintreeLibraryVersion"),
-            "Android-" + com.braintreepayments.api.core.BuildConfig.VERSION_NAME);
-        Assert.assertEquals(lookup.getString("nonce"), "a-nonce");
-        assertFalse(lookup.has("dfReferenceId"));
-
-        JSONObject clientMetaData = lookup.getJSONObject("clientMetadata");
-        Assert.assertEquals(clientMetaData.getString("requestedThreeDSecureVersion"), "2");
-        Assert.assertEquals(clientMetaData.getString("sdkVersion"),
-            "Android/" + com.braintreepayments.api.core.BuildConfig.VERSION_NAME);
+        verify(cardinalClient).initialize(same(activity), same(threeDSecureEnabledConfig),
+            same(basicRequest), any(CardinalInitializeCallback.class));
     }
 
     @Test
-    public void prepareLookup_initializesCardinal() throws BraintreeException {
+    public void prepareLookup_whenCardinalClientInitializeFails_forwardsError()
+        throws BraintreeException {
+        BraintreeException initializeRuntimeError = new BraintreeException("initialize error");
         CardinalClient cardinalClient = new MockCardinalClientBuilder()
-            .successReferenceId("fake-df")
+            .initializeRuntimeError(initializeRuntimeError)
             .build();
 
         BraintreeClient braintreeClient = new MockBraintreeClientBuilder()
@@ -190,27 +173,28 @@ public void prepareLookup_initializesCardinal() throws BraintreeException {
         ThreeDSecurePrepareLookupCallback callback = mock(ThreeDSecurePrepareLookupCallback.class);
         sut.prepareLookup(activity, basicRequest, callback);
 
-        verify(cardinalClient).initialize(same(activity), same(threeDSecureEnabledConfig),
-            same(basicRequest), any(CardinalInitializeCallback.class));
+        ArgumentCaptor<ThreeDSecurePrepareLookupResult> captor = ArgumentCaptor.forClass(ThreeDSecurePrepareLookupResult.class);
+        verify(callback).onPrepareLookupResult(captor.capture());
+        ThreeDSecurePrepareLookupResult prepareLookupResult = captor.getValue();
+        assertTrue(prepareLookupResult instanceof ThreeDSecurePrepareLookupResult.Failure);
+        assertEquals(initializeRuntimeError, ((ThreeDSecurePrepareLookupResult.Failure) prepareLookupResult).getError());
     }
 
     @Test
-    public void prepareLookup_whenCardinalClientInitializeFails_forwardsError()
-        throws BraintreeException {
-        BraintreeException initializeRuntimeError = new BraintreeException("initialize error");
+    public void prepareLookup_whenDfReferenceIdMissing_forwardsError() throws BraintreeException {
         CardinalClient cardinalClient = new MockCardinalClientBuilder()
-            .initializeRuntimeError(initializeRuntimeError)
-            .build();
+                .successReferenceId("")
+                .build();
 
         BraintreeClient braintreeClient = new MockBraintreeClientBuilder()
-            .configuration(threeDSecureEnabledConfig)
-            .build();
+                .configuration(threeDSecureEnabledConfig)
+                .build();
 
         ThreeDSecureClient sut = new ThreeDSecureClient(
-            braintreeClient,
-            cardinalClient,
-            new ThreeDSecureAPI(braintreeClient),
-            merchantRepository
+                braintreeClient,
+                cardinalClient,
+                new ThreeDSecureAPI(braintreeClient),
+                merchantRepository
         );
 
         ThreeDSecurePrepareLookupCallback callback = mock(ThreeDSecurePrepareLookupCallback.class);
@@ -220,7 +204,11 @@ public void prepareLookup_whenCardinalClientInitializeFails_forwardsError()
         verify(callback).onPrepareLookupResult(captor.capture());
         ThreeDSecurePrepareLookupResult prepareLookupResult = captor.getValue();
         assertTrue(prepareLookupResult instanceof ThreeDSecurePrepareLookupResult.Failure);
-        assertEquals(initializeRuntimeError, ((ThreeDSecurePrepareLookupResult.Failure) prepareLookupResult).getError());
+        Exception error = ((ThreeDSecurePrepareLookupResult.Failure) prepareLookupResult).getError();
+
+        TestCase.assertTrue(error instanceof BraintreeException);
+        Assert.assertEquals(error.getMessage(),
+                "There was an error retrieving the dfReferenceId.");
     }
 
     @Test