TL;DR
- LINEチャネルとトークンは有効で、コードは筆者の環境に移せば動いた。
- 確定できた問題は1点、LINEに登録されたWebhook URLが、
調査していたGASプロジェクトのものではなかったこと。 - 同じコードを持つ別プロジェクトのURLは、dogetを叩いても同じ応答を返す。
URLが応答することは、正しく繋がっている証拠にならない。 - 切り分けの決め手は、GASの「実行数」ログ。叩いてもログが増えないなら、そのURLは今見ているプロジェクトに届いていない。
何が起きたか
「グループで話しかけても、返事が来ない」。
福祉施設に導入予定のBot(GAS + LINE Messaging API + Gemini)が一度も返事をしないという相談で、担当者が2日試行錯誤したあと、筆者が調査を引き継いだ。
コードは筆者の環境で動作実績あり。LINE側の応答設定も正しい。デプロイのアクセス権も「全員」。全部シロに見えるのに、動かない。
構成は4部品しかない
LINEグループの発言
→ ① LINE側設定(Webhook利用ON・応答メッセージOFF)
→ ② Webhook URL(GASのウェブアプリURL)
→ ③ GASコード(doPost → Gemini → reply API)
→ ④ スクリプトプロパティ(トークン2つ)
→ 返信
沈黙の原因はこの4つのどれかで、それ以外はない。まず同じコードを筆者のGASと筆者のLINEチャネルで動かしたら、あっさり返事が来た。

③ GASコードはシロ。 ① LINE側設定(Webhook利用ON・応答メッセージOFF)も設定を見比べてほぼシロ。
残るは② Webhook URLと④ スクリプトプロパティ(トークン2つ)。
罠:失敗に見えるものが2つある
LINE Developersの「検証」ボタンは「302 Found」のエラーを出すが、
GASのウェブアプリはリダイレクトを返すため、正しく繋がっていてもこれは出うる。
判断材料として弱い。(筆者もこのエラー状況でBotは返事をしている)
Webhook URLをブラウザで開くと「スクリプト関数が見つかりません: doGet」と返る。デプロイは生きているように見える。だが、同じコードを持つ別プロジェクトのURLもまったく同じ応答を返す。URLの応答は、どのプロジェクトに繋がっているかを何も証明しない。
なお、ブラウザで開いた分は実行数に「doGet 失敗」として記録される。
これは故障ではない。

このコードにdoGet関数が無いため、GETは必ず失敗になる。LINEが送るのはPOSTだけなので、Botの動作にも影響しない。
ここで重要なことは、『doget』を叩いたら、『実行』に何かしらログが残ること、
そのものである。
決め手:実行数ログ
GASエディタ左メニューの「実行数」に、答えが出ていた。
このプロジェクトには、外部からdoGetを叩いた
記録が実行数に残ることを7/3以前に確認できていた。
ところが、7/5以降、LINEに登録されているURLを叩いても、ログは増えなかった。
同じ操作で、残るはずの記録が残らない。
そのURLは、今見ているプロジェクトに届いていない。
Webhookは最初から別の場所に飛んでいた これが沈黙の直接原因だった。
復旧
壊れた環境の修復には権限の壁があったため
(他人のプロジェクトはデプロイ操作を弾かれる場合がある)、
動作実証済みの筆者のGASに本番チャネルのトークンを入れて繋ぎ替えた。
作業はトークンの差し替えとURLの貼り替えの2つ、それで復旧した。
もちろん今は仮で私のGASで稼働しているので、将来的には相手方施設のドライブに
お引越しをする必要はあるだろう。
想定外のURLがどの操作で登録されたのかは、
最後まで特定できていない。
多重ログイン自体が毒というより、
「意図しないアカウントでGASを開いてデプロイしてしまう」 とURLが曖昧になる。
①トラブル対応中に「新しいデプロイの発行し直し」「別アカウントでのGAS作り直し」が繰り返され、URLとプロジェクトの数が増えていたこと、
②そして増やしたあとに『実行数』で「通信が届いたか」を確認する手順がなかったこと。
・・・『AIの対処療法の構造の穴』として言えるのはここまで、
それで対策には十分だった。
経緯の解明と問題の解決は、切り離していい。
APIで配線を確認する
トークンさえあれば、相手の画面を見なくても配線を確認できる。
function 診断() {
const token = PropertiesService.getScriptProperties().getProperty('LINE_ACCESS_TOKEN');
const opt = { headers: { Authorization: 'Bearer ' + token }, muteHttpExceptions: true };
const info = UrlFetchApp.fetch('https://api.line.me/v2/bot/info', opt);
console.log('① bot info: ' + info.getContentText());
const ep = UrlFetchApp.fetch('https://api.line.me/v2/bot/channel/webhook/endpoint', opt);
console.log('② webhook: ' + ep.getContentText());
}
- ①が401 → トークンが無効
- ①のdisplayNameが想定と違う → チャネルの取り違え
- ②のendpointが想定と違う → URLの取り違え。
active: falseならWebhook利用がOFF
復旧後にこの診断を元の環境で実行したところ、トークンは有効だった。壊れていたと確定できたのは、やはりURLの接続だけだった。
予防策
- コードの更新は「デプロイを管理」から既存デプロイの編集で行う。
URLが変わらないので、貼り替え作業そのものが消える。
「新しいデプロイ」はURLを変えたい時だけ。 - URLを貼り替えたら、実行数ログで「ログが増えること」をその場で確認する。
doget応答が返ることは確認にならない。 - AIによる対処法リストを実行する前に『この手順のどこで、直ったと確認できるのか』を問う。
確認手順のない対処法は、状態を変えるだけで何も教えてくれない。
チェックリスト(Botが沈黙したとき)
- 「実行数」を開き、メッセージ送信の直後に新しい行が増えるかを見る
- 増えない → 通信が届いていない。Webhook URLとLINE側の「Webhookの利用」を疑う
- 増えて「失敗」 → 通信は届いている。コードかスクリプトプロパティを疑う
- 実行数の「doGet 失敗」に慌てない。ブラウザでURLを開いた痕跡で、doGet関数が無いコードでは仕様。むしろ「叩けばログに残る」ことの確認になる
- URLが応答しても、正しく繋がっている証拠にしない
- 「検証」の302だけで不通と断定しない。成否は実行数ログで見る
- デプロイ前に、右上のアカウントと開いているプロジェクト名を見る。別プロジェクトのURLを貼ると、沈黙するか、「管理していないプロジェクトが本番として動く」かのどちらかになる
- 壊れた環境に固執しない。実証済みのGASとトークンへの差し替えで、経緯不明のまま復旧できる


