
GAS로 만든 LINE Bot이 무반응인 이유: 'LINE에 등록된 Webhook URL'과 '보고 있는 GAS 프로젝트'의 불일치
요약
Google Apps Script(GAS)를 이용한 LINE Bot 개발 시 Webhook URL 불일치로 인해 발생하는 무반응 문제를 다룹니다. URL의 응답 여부보다 GAS의 '실행 수(Executions)' 로그를 통해 실제 호출 여부를 확인하는 것이 중요함을 강조합니다.
핵심 포인트
- Webhook URL의 응답이 성공적이라도 실제 프로젝트와 연결되지 않았을 수 있음
- GAS의 '실행 수(Executions)' 로그가 호출 여부를 판단하는 가장 확실한 지표임
- LINE Developers의 '검증(Verify)' 버튼 에러는 리다이렉트 특성상 오탐일 수 있음
- doGet 함수 부재로 인한 에러는 POST 방식인 Webhook 동작에 영향을 주지 않음
- LINE 채널과 토큰은 유효하며, 코드를 필자의 환경으로 옮기면 동작했다.
- 확정된 문제는 단 한 가지,
LINE에 등록된 Webhook URL이 다르다는 것.
조사하던 GAS 프로젝트의 것이 아니었다 - 동일한 코드를 가진 다른 프로젝트의 URL은, doGet을 호출해도 똑같은 응답을 반환한다.
URL이 응답한다고 해서 올바르게 연결되어 있다는 증거는 되지 않는다. - 구분 짓는 결정적인 단서는 GAS의 「실행 수 (Execution)」 로그다. 호출해도 로그가 늘어나지 않는다면, 그 URL은 현재 보고 있는 프로젝트에 도달하지 않고 있는 것이다.
"그룹에서 말을 걸어도 답장이 오지 않는다".
복지 시설에 도입 예정인 Bot (GAS + LINE Messaging API + Gemini)이 한 번도 답장을 하지 않는다는 상담을 받고, 담당자가 2일간 시행착오를 겪은 후 필자가 조사를 인계받았다.
코드는 필자의 환경에서 동작 실적이 있다. LINE 측의 응답 설정도 올바르다. 배포(Deploy)의 액세스 권한도 「모두(Everyone)」다. 모든 것이 정상(White)으로 보이는데, 동작하지 않는다.
LINE 그룹의 발언
→ ① LINE 측 설정 (Webhook 이용 ON · 응답 메시지 OFF)
→ ② Webhook URL (GAS의 웹 앱 URL)
...
침묵의 원인은 이 4가지 중 하나이며, 그 외에는 없다. 우선 동일한 코드를 필자의 GAS와 필자의 LINE 채널에서 실행했더니, 아주 쉽게 답장이 왔다.

③ GAS 코드는 정상이다. ① LINE 측 설정 (Webhook 이용 ON · 응답 메시지 OFF)도 설정을 비교해 보니 거의 정상이다.
남은 것은 ② Webhook URL과 ④ 스크립트 속성 (Script Properties, 토큰 2개)이다.
LINE Developers의 「검증 (Verify)」 버튼은 「302 Found」 에러를 내보내지만,
GAS의 웹 앱은 리다이렉트(Redirect)를 반환하기 때문에, 올바르게 연결되어 있어도 이 에러가 발생할 수 있다.
판단 자료로서는 약하다. (필자도 이 에러 상황에서 Bot은 답장을 하고 있다.)
Webhook URL을 브라우저에서 열면 「스크립트 함수를 찾을 수 없습니다: doGet」이라고 반환된다. 배포는 살아있는 것처럼 보인다. 하지만 동일한 코드를 가진 다른 프로젝트의 URL도 완전히 똑같은 응답을 반환한다. URL의 응답은 어느 프로젝트에 연결되어 있는지를 아무것도 증명하지 않는다.
참고로, 브라우저에서 연 부분은 실행 수에 「doGet 실패」로 기록된다.
이것은 고장이 아니다.

이 코드에 doGet 함수가 없기 때문에, GET 요청은 반드시 실패한다. LINE이 보내는 것은 POST뿐이므로, Bot의 동작에도 영향을 주지 않는다.
GAS 에디터 왼쪽 메뉴의 「실행 수 (Executions)」에 답이 있었다.
이 프로젝트에는 외부에서 doGet을 호출했을 때
기록이 실행 수에 남는 것을 7/3 이전에 확인했었다.
그런데 7/5 이후, LINE에 등록된 URL을 호출해도 로그가 늘어나지 않았다.
동일한 조작을 해도 남아야 할 기록이 남지 않는다. 그 URL은 지금 보고 있는 프로젝트에 도달하지 않고 있다. Webhook은 처음부터 다른 곳으로 날아가고 있었다. 이것이 침묵의 직접적인 원인이었다.
망가진 환경을 복구하기에는 권한의 벽이 있었기에
(타인의 프로젝트는 배포 조작이 차단되는 경우가 있음),
동작 실증이 완료된 필자의 GAS에 본방 채널의 토큰을 넣어 교체했다.
작업은 토큰 교체와 URL 붙여넣기 두 가지였다. 그것으로 복구되었다.
예상치 못한 URL이 어떤 조작으로 등록되었는지는
끝까지 특정하지 못했다.
① 트러블 대응 중에 「새로운 배포의 재발행」, 「다른 계정으로 GAS 다시 만들기」가 반복되어 URL과 프로젝트의 수가 늘어나고 있었다는 점,
② 그리고 늘린 후에 『실행 수』에서 「통신이 도달했는지」를 확인하는 절차가 없었다는 점.
・・・『AI의 대처 요법 구조적 결함』으로서 말할 수 있는 것은 여기까지이며,
그것으로 대책에는 충분했다.
경위의 해명과 문제의 해결은 분리해도 좋다.
토큰만 있다면 상대방의 화면을 보지 않고도 배선을 확인할 수 있다.
function 진단() {
const token = PropertiesService.getScriptProperties().getProperty('LINE_ACCESS_TOKEN');
const opt = { headers: { Authorization: 'Bearer ' + token }, muteHttpExceptions: true };
...
- ①가 401 → 토큰이 무효함
- ①의 displayName이 예상과 다름 → 채널을 잘못 선택함
- ②의 endpoint가 예상과 다름 → URL을 잘못 선택함.
active: false
Webhook 이용이 OFF 상태라면
복구 후 원래 환경에서 이 진단을 실행했을 때, 토큰은 유효했다. 결국 URL의 연결만이 문제였다는 것을 확정할 수 있었다.
- 코드 업데이트는 「배포 관리 (Manage deployments)」에서 기존 배포를 편집하여 수행한다.
URL이 바뀌지 않으므로, URL을 다시 붙여넣는 작업 자체가 사라진다.
「새 배포 (New deployment)」는 URL을 바꾸고 싶을 때만 사용한다. - URL을 다시 붙여넣었다면, 실행수 로그에서 「로그가 늘어나는 것」을 그 자리에서 확인한다.
doget 응답이 돌아오는 것은 확인 방법이 아니다. - AI가 제시하는 대처법 리스트를 실행하기 전에 『이 절차의 어느 단계에서, 고쳐졌음을 확인할 수 있는가』를 물어야 한다.
확인 절차가 없는 대처법은 상태를 바꿀 뿐, 아무것도 알려주지 않는다.
- 「실행수 (Executions)」를 열고, 메시지 전송 직후에 새로운 행이 늘어나는지 확인한다.
- 늘어나지 않음 → 통신이 도달하지 않음. Webhook URL과 LINE 측의 「Webhook 이용」 설정을 의심한다.
- 늘어나고 「실패 (Failed)」 → 통신은 도달함. 코드나 스크립트 속성 (Script Properties)을 의심한다.
- 실행수의 「doGet 실패」에 당황하지 않는다. 브라우저에서 URL을 열었을 때 doGet 함수가 없는 코드라면 발생하는 사양이다. 오히려 「호출하면 로그에 남는다」는 사실을 확인하는 과정이다.
- URL이 응답한다고 해서, 올바르게 연결되어 있다는 증거로 삼지 않는다.
- 「검증 (Verify)」 버튼의 302 응답만으로 통신 불능이라고 단정하지 않는다. 성패는 실행수 로그로 확인한다.
- 배포 전에, 우측 상단의 계정과 열려 있는 프로젝트 이름을 확인한다. 다른 프로젝트의 URL을 붙여넣으면, 응답이 없거나 「관리하지 않는 프로젝트가 운영 환경으로서 동작하는」 상황 중 하나가 발생한다.
- 고장 난 환경에 집착하지 않는다. 검증된 GAS와 토큰으로 교체함으로써, 경위를 알 수 없는 상태에서도 복구할 수 있다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기