flutterfire icon indicating copy to clipboard operation
flutterfire copied to clipboard

[cloud_firestore]: Double is not a subtype of int

Open larssn opened this issue 1 year ago • 12 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues.

Which plugins are affected?

Core

Which platforms are affected?

Android

Description

So I've just run into the issue described in #12436, and this is using cloud_firestore_platform_interface: 6.2.2.

The "fix" was changing the int directly in firestore (away from 0 and back to 0), which caused the issue to go away.

Reproducing the issue

Not sure, I'm just FieldValue.increment(ing) integers with integers.

Firebase Core version

2.30.1

Flutter Version

3.19.6

Relevant Log Output

No response

Flutter dependencies

Workspace Environment
Dart Code extension: 3.88.0
Flutter extension: 3.88.0 (activated)

App: Visual Studio Code
App Host: desktop
Version: mac 1.89.0

Workspace type: Flutter (LSP)

Dart (3.3.4): /Users/lars/fvm/versions/stable/bin/cache/dart-sdk
Flutter (3.19.6): /Users/lars/fvm/versions/stable (SM T510 (android-arm/android))

Output from 'dart info'

/Users/lars/fvm/versions/stable/bin/cache/dart-sdk/bin/dart info

If providing this information as part of reporting a bug, please review the information below to ensure it only contains things you're comfortable posting publicly.

General info

  • Dart 3.3.4 (stable) (Tue Apr 16 19:56:12 2024 +0000) on "macos_arm64"
  • on macos / Version 14.4.1 (Build 23E224)
  • locale is en-US

Project info

  • sdk constraint: '>=3.3.3 <4.0.0'
  • dependencies: android_id, audioplayers, bloc, built_collection, built_value, cached_network_image, cloud_firestore, cloud_firestore_platform_interface, collection, country_pickers, crypto, dart_date, decimal, device_info_plus, expansion_widget, file_picker, firebase_analytics, firebase_auth, firebase_core, firebase_crashlytics, firebase_storage, firebase_ui_firestore, flutter, flutter_bloc, flutter_dotenv, flutter_html, flutter_keyboard_visibility, flutter_localizations, flutter_material_color_picker, flutter_nfc_kit, flutter_riverpod, flutter_slidable, flutter_timezone, geography, html_unescape, http, image, image_picker, in_app_update, internet_connection_checker, intl, meta, package_info_plus, path_provider, phone_numbers_parser, pointycastle, positioned_tap_detector_2, qr_flutter, random_string, rational, reorderables, retry, rxdart, shared_preferences, sprintf, time, timezone, url_launcher, uuid, validators, xml
  • dev_dependencies: build_runner, built_value_generator, flutter_lints
  • elided dependencies: 13

Process info

Memory CPU Elapsed time Command line
62 MB 0.0% 49:23 dart devtools --no-launch-browser
25 MB 0.0% 19:55:12 dart devtools --no-launch-browser
4652 MB 0.0% 19:07:10 dart language-server --protocol=lsp --client-id=VS-Code --client-version=3.88.0
63 MB 0.0% 19:07:10 flutter_tools.snapshot daemon
253 MB 0.0% 50:09 flutter_tools.snapshot run --machine --start-paused -d R52N70RYCGL --target lib/main.dart
Output from 'flutter doctor'

/Users/lars/fvm/versions/stable/bin/flutter doctor -v

[✓] Flutter (Channel stable, 3.19.6, on macOS 14.4.1 23E224 darwin-arm64, locale en-US)
    • Flutter version 3.19.6 on channel stable at /Users/lars/fvm/versions/stable
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 54e66469a9 (3 weeks ago), 2024-04-17 13:08:03 -0700
    • Engine revision c4cd48e186
    • Dart version 3.3.4
    • DevTools version 2.31.1

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/lars/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/lars/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11572160)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15E204a
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11572160)

[✓] VS Code (version 1.89.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.88.0

[✓] Connected device (5 available)
    • A920Pro (mobile)       • 1851510595                • android-arm    • Android 8.1.0 (API 27)
    • SM T510 (mobile)       • R52N70RYCGL               • android-arm    • Android 11 (API 30)
    • Another Phone (mobile) • 00008110-000404840C7A801E • ios            • iOS 17.4.1 21E236
    • macOS (desktop)        • macos                     • darwin-arm64   • macOS 14.4.1 23E224 darwin-arm64
    • Chrome (web)           • chrome                    • web-javascript • Google Chrome 124.0.6367.119

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Additional context and comments

No response

larssn avatar May 08 '24 08:05 larssn

Hello @larssn, thank you for reporting this issue. I wasn't able to reproduce it. Here's the code I used, and it ran without errors:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  FirebaseFirestore.instance.settings = const Settings(
    persistenceEnabled: true,
  );
  if (shouldUseFirestoreEmulator) {
    FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
  }

  runApp(TheApp());
}


class TheApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              try {
                // Update operation
                FirebaseFirestore firestore = FirebaseFirestore.instance;
                DocumentReference documentReference =
                firestore.collection('test_10153').doc('counter');
                final doc = await documentReference.get();
                if (!doc.exists) {
                  await documentReference.set(<String, dynamic>{});
                }
                await documentReference.update({'counter': FieldValue.increment(1)});

                // Attempt to fetch and deserialize the updated document
                DocumentSnapshot snapshot = await documentReference.get();
                Map<dynamic, dynamic>? data = snapshot.data() as Map<dynamic, dynamic>?;
                if (data != null) {
                  // Directly deserialize 'counter' field within fromFirestore
                  int? counter = data['counter'] as int?;
                  print('Deserialized counter value: $counter');
                }
              } on Exception catch (error, stackTrace) {
                debugPrint(error.toString());
                debugPrintStack(stackTrace: stackTrace);
              }
            },
            child: Text('Increment Counter and Deserialize'),
          ),
        ),
      ),
    );
  }
}

I suggest you update all your plugins to the latest version and try again. If the issue still persists, please provide a reproduction code or repo that is failing.

TarekkMA avatar May 08 '24 11:05 TarekkMA

They are all the latest version, and I just experienced this issue today.

And I have used FieldValue.increment without issues, but the error seems periodic.

larssn avatar May 08 '24 11:05 larssn

What's the size of the vlaue you are trying to increment and by how much you are incrementing it?

TarekkMA avatar May 08 '24 13:05 TarekkMA

Not much, in my tests I used about -5 to +5. And the size incremented/subtracted, is about the same.

larssn avatar May 09 '24 13:05 larssn

I'm seeing a kind of similar issue:

_TypeError: type 'int' is not a subtype of type 'double' in type cast

This happens at this line:

    final double graceAmount = snap.get('grace_amount') != null ? snap.get('grace_amount') as double : 0;

The thing is this still works fine for most of my users. Meaning snap.get('grace_amount') returns 0.0 for most of them. But yesterday when I tried to copy all the documents of a user to another, the new user encounter this issue. For this case snap.get('grace_amount') returns 0. So I guess something has changed from firestore end.

This is the firebase function that I used:

    const { sourceUserID, destUserID } = request.body;

    if (!sourceUserID || !destUserID) {
      logger.warn("Missing sourceUserID or destUserID.");
      response.sendStatus(400);
    }
    try {
      const sourceRef = getFirestore().collection("users").doc(sourceUserID);
      const destRef = getFirestore().collection("users").doc(destUserID);

      // Copy subcollections
      const sourceCollections = await sourceRef.listCollections();
      for (const collection of sourceCollections) {
        const collectionRef = sourceRef.collection(collection.id);
        const destCollectionRef = destRef.collection(collection.id);

        const collectionSnapshot = await collectionRef.get();
        for (const doc of collectionSnapshot.docs) {
          await destCollectionRef.doc(doc.id).set(doc.data(), { merge: true });
        }
      }
      logger.info("Documents copied successfully");
    } catch (error) {
      logger.error("Error copying documents");
    }

minhdanh avatar May 10 '24 01:05 minhdanh

I guess I figured it out. Using Typescript/Javascript, it was impossible for me to explicitly use a double type for numbers without the fractional part, like 0, 10, 123, etc. I was able to do that with Dart, that's why my normal users don't experience the problem. Furthermore the Firebase consol only shows the values as "number" is something that made it more confusing to me when there're actually 2 types of number supported: https://firebase.google.com/docs/firestore/manage-data/data-types

I had to use a Python function to do the copy. Problem fixed.

minhdanh avatar May 10 '24 10:05 minhdanh

@minhdanh Thank you for sharing these details, appreciated.


@larssn Can you investigate if your issue is similar to the one @minhdanh mentioned? Since I couldn't get issue to happen when testing.

TarekkMA avatar May 10 '24 12:05 TarekkMA

Ours is in pure dart, no web involved, so I doubt it's the same issue.

The "fix" was changing the int directly in firestore (away from 0 and back to 0), which caused the issue to go away.

I still think this part was weird, and is probably significant.

larssn avatar May 10 '24 13:05 larssn

for me I simply us num instead of int and then num.toInt()

Tr736 avatar May 14 '24 08:05 Tr736

We use the workaround on incoming data as well, but I'd prefer we wouldn't have to.

larssn avatar May 14 '24 08:05 larssn

Today, the DocumentSnapshotData is reading every int as double.

Like, "x": 1,

its giving on the runtime x=1.0

rogerfsg avatar Jun 06 '24 14:06 rogerfsg