Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

[cloud_firestore][Windows] Transaction read and commit errors lose the Firestore error code (reported as `unknown`)

クローズ 初心者向け
#18,735 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
84/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
dart

調査の方向性

windows/cloud_firestore_plugin.cpp の TransactionGet とトランザクション完了ハンドラーから始め、両方のパスを ParseError と比較します。読み取りを拒否するルールを使用して Windows で再現し、トランザクションの読み取りと失敗したコミットが unknown ではなく Firestore のエラーコードとメッセージを報告することを確認します。提供された Dart のトランザクション例と関連する Windows プラグインのチェックで変更を確認します。

索引モデルが issue の本文から書いたものです。

説明

Needs Attention platform: windows plugin: cloud_firestore reproduced type: bug
Is there an existing issue for this?
  • I have searched the existing issues.

This is the same class of defect as #18550 (firebase_database on Windows), in cloud_firestore.

Which plugins are affected?

Other (Cloud Firestore)

Which platforms are affected?

Windows

Description

On Windows, a Firestore transaction that fails reaches Dart as FirebaseException(code: 'unknown') whatever Firestore actually returned. The same failure on a plain DocumentReference.get() reports the real code (permission-denied, unavailable, …), because that path goes through ParseError.

Two paths in windows/cloud_firestore_plugin.cpp build their error without the details map that ParseError provides:

  1. TransactionGet, a read inside a transaction (L1260 at a646d55):

    result(FlutterError(error_message));
    

    That is the one-argument constructor, so the Firestore message lands in the error's code slot, with no message and no details.

  2. The transaction completion handler, when the commit fails (L1160):

    SendErrorOnPlatformThread(events_state_, "transaction_error",
                              completed_future.error_message(),
                              flutter::EncodableValue());
    

_flutterfire_internals' platformExceptionToFirebaseException reads the code only from details['code'] and falls back to unknown. It reads the message from details['message'], or else PlatformException.message. So:

  • a failed transaction read becomes [cloud_firestore/unknown] with an empty message, because the real message went into PlatformException.code, which is discarded;
  • a failed commit becomes [cloud_firestore/unknown], keeping the message but not the code.

Apps can't tell a rules or App Check refusal (permission-denied) from contention (aborted) or a transient network failure. Anything that retries or reports on the code misclassifies it: we retried a permanent permission-denied as if it were transient.

Observed: the read path in production, from a Windows desktop app. The stack ran through FirebaseFirestoreHostApi.transactionGet → MethodChannelTransaction.get and ended in FirebaseException: [cloud_firestore/unknown] with no message. Earlier in the same session, the same account's plain get() of another document failed with [cloud_firestore/permission-denied]. The commit path is from reading the code; it has the same shape.

Suggested fix (not yet compiled on Windows), giving both paths the shape ParseError already uses:

@@ TransactionStreamHandler completion
           } else {
+            EncodableMap details;
+            details[EncodableValue("code")] =
+                EncodableValue(CloudFirestorePlugin::GetErrorCode(
+                    static_cast<firebase::firestore::Error>(
+                        completed_future.error())));
+            details[EncodableValue("message")] =
+                EncodableValue(completed_future.error_message());
             SendErrorOnPlatformThread(events_state_, "transaction_error",
                                       completed_future.error_message(),
-                                      flutter::EncodableValue());
+                                      EncodableValue(details));
           }
@@ void CloudFirestorePlugin::TransactionGet(
   if (error_code != Error::kErrorOk) {
-    result(FlutterError(error_message));
+    EncodableMap details;
+    details[EncodableValue("code")] = EncodableValue(GetErrorCode(error_code));
+    details[EncodableValue("message")] = EncodableValue(error_message);
+    result(FlutterError("firebase_firestore", error_message, details));
   } else {
Reproducing the issue

On Windows, with rules that deny reading a document:

match /denied/{doc} { allow read: if false; }
try {
  await FirebaseFirestore.instance.runTransaction((tx) async {
    await tx.get(FirebaseFirestore.instance.doc('denied/doc'));
  });
} on FirebaseException catch (e) {
  print('${e.code}: ${e.message}');
}
  • Expected: permission-denied: Missing or insufficient permissions., as the same read outside a transaction reports.
  • Actual: unknown: (empty message).

A transaction whose write is denied by rules shows the commit path: the code is unknown and the message is kept.

Firebase Core version

4.13.0 (cloud_firestore 6.8.0; the code is unchanged in 6.9.0 and on main at a646d55)

Flutter Version

3.47.4 (Dart 3.13.3)

Relevant Log Output
FirebaseException: [cloud_firestore/unknown]
_extractReplyValueOrThrow (messages.pigeon.dart:27)
FirebaseFirestoreHostApi.transactionGet (messages.pigeon.dart:1477)
MethodChannelTransaction.get (method_channel_transaction.dart:50)
Transaction.get (transaction.dart:28)
Flutter dependencies

cloud_firestore 6.8.0, cloud_firestore_platform_interface 8.0.6, _flutterfire_internals 1.3.76, firebase_core 4.13.0. Windows 11 (build 26200), release build.

Additional context and comments

Every other error path in the file builds details itself (ParseError, the bundle loader), so this looks like two call sites that were missed rather than a design choice.

主要言語
Dart
スター
9.3k
フォーク
4.1k
平均マージ
3日 4時間
マージ済み PR(30日)
56

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

firebase/flutterfire のほかの issue

firebase/flutterfire の issue をすべて見る

似ている issue

Dart の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。