同事象で苦しむ人は稀と思われるので、この記録が役に立つかは不明。

発端

  • Serverless Framework にて AWS Lambda 上で動くコードを開発中。
  • serverless-offline にて、ローカルで起動している Firebase Local Emulator の Cloud Firestore に以下のコードを実行するとエラーが発生。

(試してはいませんが、ローカル環境で上記が発生している場合、デプロイ後の本番の Lambda 上でも同様にエラーとなるはずです。)

import admin from 'firebase-admin';
import serviceAccount from '***-firebase-adminsdk.json';

admin.initializeApp({ credential: admin.credential.cert(serviceAccount as admin.ServiceAccount) });

const docData = {
  stringExample: 'Hello world!',
  booleanExample: true,
  numberExample: 3.14159265,
  dateExample: admin.firestore.FieldValue.serverTimestamp(),
  arrayExample: [5, true, 'hello'],
  nullExample: null,
  objectExample: {
    a: 5,
    b: {
      nested: 'foo',
    },
  },
};

db.collection('data').doc('one').set(docData);

エラーメッセージは以下

Request message serialization failure: util.Long.fromValue is not a function

送っているパラメータを一つずつ確認していくと、どうやら以下の3つを送ろうとすると上記エラーになる。タイムスタンプと配列とマップがダメな様子。

  • dateExample
  • arrayExample
  • objectExample

原因

いろいろ調べてみると下記が原因だった。(参考にしたソースは本記事の最後にまとめます。)

  • node モジュールの firebase-admin の依存先を辿っていくと、依存パッケージの一つに long がある。バージョンは 4.0.0 以上が指定されている。
  • serverless の依存先を辿っていくと、これも依存パッケージの一つに long がある。バージョンは 1.1.2 が指定されている。
  • 古いバージョンの long(< 2.1.0) には fromValue method が存在しない。
  • package.lock.json で最終的に指定されている long を見ると以下になっていた。
"long": {
  "version": "1.1.2",
  "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz",
  "integrity": "sha1-6u9ZUcp1UdlpJrgtokLbnWso+1M=",
  "dev": true
},

ご覧の通り 1.1.2 の方が適用されている。

理由

  • 古いバージョンと新しいバージョンの long どちらが最終的に適用されるかは、 package-lock.json 内で読み込む順番によって決まり、先に読み込んだ方が適用される。
  • 私の場合、package-lock.json では serverless の方が firebase-admin よりも先に記載されており、そのため 1.1.2 の long が最終的に適用されていた。

解決策

  • 新しいバージョンの long を適用させる必要がある。
  • そのためには、 firebase-adminserverless よりも先に記載すれば良い。
  • package-lock.json へ記載される順番は、 npm install した順番によって決まるため、まずは npm i firebase-admin その後 npm i serverless すれば良い。

なお、 package.json では dependenciesfirebase-admin を、 devDependenciesserverless を 指定しているのが通常と思われるが、その状態であれば、一度 package-lock.json を削除した後 npm install すれば firebase-admin の方が上位に記載されているはず。

原因振り返り

私の場合は、まず npm install --save-dev serverless し、その後 npm install firebase-admin していたため、本事象が発生する状態となっていた。

解決後の状態

package-lock.json を確認すると、 long のバージョンが 4.0.0 になっていることが確認できた。firebase-admin を利用したコードも問題なく動いた。

"long": {
  "version": "4.0.0",
  "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
  "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},

参考資料