← กลับไปที่บล็อก
ระบบจองผ่าน LINELINE LIFFDevelopment

แก้ liff.init error: INIT_FAILED, INVALID_CONFIG และปัญหา LIFF ที่เจอบ่อย

20 ตุลาคม 2569 · โดย Yunmin Shin

ตอบสั้น ๆ

เมื่อ liff.init() ล้มเหลว Promise จะ reject พร้อม LiffError ที่มี code บอกสาเหตุ ให้ดู code ก่อนเสมอ แล้วเทียบกับตารางด้านล่าง ปัญหาส่วนใหญ่มาจาก 3 อย่าง: liffId ผิดหรือว่าง, หน้าเว็บไม่ได้อยู่ใต้ Endpoint URL, และเรียก LIFF ฝั่ง server

import liff from "@line/liff";

try {
  await liff.init({ liffId: process.env.NEXT_PUBLIC_LIFF_ID! });
} catch (err) {
  // err.code เช่น "INIT_FAILED", "INVALID_CONFIG"
  console.error(err.code, err.message);
}

ตาราง error code ของ liff.init

| code | ความหมายตามเอกสาร LINE | สาเหตุที่เจอบ่อยจริง | |---|---|---| | INIT_FAILED | เริ่ม LIFF SDK ไม่สำเร็จ | หน้าไม่ได้อยู่ใต้ Endpoint URL, ใช้ http, เรียก init ซ้ำ | | INVALID_CONFIG | การตั้งค่าไม่ถูกต้อง | ไม่ได้ส่ง liffId, env variable ว่างตอน build | | INVALID_ARGUMENT | ส่ง argument ผิด | ส่ง option ผิดรูปแบบ | | UNAUTHORIZED | ผู้ใช้ไม่ได้อนุญาต หรือเรียก API โดยไม่มี access token | ผู้ใช้กดปฏิเสธหน้าขอสิทธิ์ | | FORBIDDEN | ไม่มีสิทธิ์ หรือใช้ฟีเจอร์ในสภาพแวดล้อมที่ไม่รองรับ | ไม่ได้เปิด scope, เรียกคำสั่งที่ใช้ได้เฉพาะในแอป LINE จากเบราว์เซอร์ข้างนอก | | INVALID_ID_TOKEN | ตรวจสอบ ID token ไม่ผ่าน | token หมดอายุ | | EXCEPTION_IN_SUBWINDOW | ปัญหาในหน้าต่างย่อย | เปิด target picker ค้างไว้เกิน 10 นาที | | UNKNOWN | ไม่ทราบสาเหตุ | ลองเช็กเวอร์ชัน SDK และเวอร์ชันแอป LINE |

ที่มา: LIFF API reference ตรวจสอบเมื่อ 20 ตุลาคม 2569

สาเหตุที่ 1: liffId ว่างหรือผิด

LIFF ID มีรูปแบบ 1234567890-AbCdEfGh หาได้ที่แท็บ LIFF ของ channel ใน LINE Developers Console

กับดักที่เจอบ่อยที่สุดใน Next.js คือ env variable ที่ใช้ในฝั่ง client ต้องขึ้นต้นด้วย NEXT_PUBLIC_ และถูกฝังค่าตอน build ถ้าเพิ่ม env หลัง build แล้วไม่ build ใหม่ ค่าที่ได้จะเป็น undefined และ init จะล้มด้วย INVALID_CONFIG

วิธีเช็กเร็ว: console.log(process.env.NEXT_PUBLIC_LIFF_ID) ก่อนเรียก init

สาเหตุที่ 2: หน้าเว็บไม่ได้อยู่ใต้ Endpoint URL

ถ้าลงทะเบียน Endpoint URL ไว้เป็น https://book.example.com/liff/ แต่เปิดหน้า https://book.example.com/booking init จะล้ม เพราะหน้านั้นไม่ได้อยู่ใต้ path ที่ลงทะเบียน

  • ใช้ https เท่านั้น
  • ให้ลูกค้าเปิดผ่าน LIFF URL https://liff.line.me/LIFF_ID ไม่ใช่ URL ของเว็บตรง ๆ
  • ตอนพัฒนาบนเครื่อง ใช้ tunnel ที่ให้ https เช่น ngrok ซึ่ง LIFF CLI รองรับอย่างเป็นทางการ แล้วอัปเดต Endpoint URL ของ LIFF app สำหรับทดสอบ (แยก LIFF app สำหรับ dev กับ production)

สาเหตุที่ 3: เรียก LIFF ฝั่ง server (Next.js)

LIFF SDK ต้องใช้ window จึงทำงานได้เฉพาะในเบราว์เซอร์ ถ้า import แล้วเรียกระหว่าง server rendering จะได้ window is not defined

"use client";
import { useEffect, useState } from "react";

export function useLiff(liffId: string) {
  const [ready, setReady] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    import("@line/liff").then(({ default: liff }) =>
      liff.init({ liffId })
        .then(() => {
          if (!liff.isLoggedIn()) liff.login();
          else if (!cancelled) setReady(true);
        })
        .catch(e => !cancelled && setError(e.code ?? String(e))),
    );
    return () => { cancelled = true };
  }, [liffId]);

  return { ready, error };
}

ใน development โหมด React Strict Mode จะเรียก useEffect สองครั้ง ตัวแปร cancelled ช่วยไม่ให้ state ซ้อนกัน

สาเหตุที่ 4: ใช้ได้ใน LINE แต่พังในเบราว์เซอร์

ในแอป LINE ผู้ใช้ล็อกอินอยู่แล้ว แต่ใน Chrome หรือ Safari ยังไม่ได้ล็อกอิน ให้เช็ก liff.isLoggedIn() หลัง init และเรียก liff.login() ถ้ายังไม่ล็อกอิน

บางคำสั่งใช้ได้เฉพาะในแอป LINE เช่น liff.sendMessages() ใช้ liff.isInClient() เช็กก่อน แล้วเตรียมทางสำรองไว้ เช่น ส่งยืนยันการจองจากหลังบ้านแทน

สาเหตุที่ 5: liff.ready ไม่จับ error

liff.ready เป็น Promise ที่ resolve เมื่อ init สำเร็จ แต่ จะไม่ reject เมื่อ init ล้มเหลว ตามที่เอกสาร LINE ระบุ ถ้าโค้ดรอแค่ liff.ready หน้าจะค้างโดยไม่มี error ให้เห็น ต้องจับ error จาก liff.init() โดยตรง

เช็กลิสต์ก่อนส่งงาน

  • [ ] liffId ของ production ถูกต้อง และไม่ใช่ของ dev
  • [ ] Endpoint URL เป็น https และครอบคลุมทุกหน้าที่ใช้ LIFF
  • [ ] เปิด scope ที่ต้องใช้: profile, openid และ chat_message.write ถ้าใช้ sendMessages
  • [ ] LIFF app และ LINE OA อยู่ใต้ provider เดียวกัน
  • [ ] ทดสอบทั้งในแอป LINE (iOS และ Android) และในเบราว์เซอร์ภายนอก

อ่านต่อ: liff.getProfile และ userId · LIFF กับ LINE MINI App ต่างกันอย่างไร

ไม่อยากแก้บั๊กเอง ให้เราทำระบบจองผ่าน LINE ให้ทั้งระบบ ดู ระบบจองคิวผ่าน LINE OA

คำถามที่พบบ่อย

liff.init error INVALID_CONFIG เกิดจากอะไร?

ตามเอกสาร LIFF API ของ LINE เกิดจากการตั้งค่าผิด เช่น ไม่ได้ส่ง liffId เข้า liff.init() หรือ URL ที่ใช้กับ liff.permanentLink.createUrl() ไม่ได้ขึ้นต้นด้วย Endpoint URL ที่ลงทะเบียนไว้ ให้ตรวจว่า liffId ถูกต้องและไม่ว่าง โดยเฉพาะเมื่ออ่านจาก environment variable

liff.init error INIT_FAILED แก้อย่างไร?

INIT_FAILED หมายถึงเริ่ม LIFF SDK ไม่สำเร็จ สาเหตุที่พบบ่อยคือหน้าเว็บไม่ได้อยู่ใต้ Endpoint URL ที่ลงทะเบียนไว้ ใช้ http แทน https หรือเรียก liff.init ซ้ำหลายครั้ง ให้เปิดหน้าผ่าน LIFF URL (https://liff.line.me/LIFF_ID) และเรียก init ครั้งเดียวต่อการโหลดหน้า

ทำไม LIFF ใช้ได้ในแอป LINE แต่เปิดใน Chrome แล้วพัง?

เพราะในเบราว์เซอร์ภายนอก ผู้ใช้ยังไม่ได้ล็อกอิน LINE ต้องตรวจ liff.isLoggedIn() หลัง init แล้วเรียก liff.login() ถ้ายังไม่ล็อกอิน และบางคำสั่ง เช่น liff.sendMessages() ใช้ได้เฉพาะในแอป LINE เท่านั้น

ใช้ LIFF กับ Next.js แล้วขึ้น window is not defined ทำอย่างไร?

LIFF SDK ทำงานได้เฉพาะในเบราว์เซอร์ ให้เรียก liff.init ใน client component ภายใน useEffect หรือ import แบบ dynamic import('@line/liff') ภายใน useEffect ห้ามเรียกระหว่าง server rendering

liff.ready ช่วยจับ error ได้ไหม?

ไม่ได้ ตามเอกสารของ LINE liff.ready จะไม่ถูก reject เมื่อ liff.init ล้มเหลว ต้องจับ error จาก Promise ของ liff.init() เองด้วย try/catch หรือ .catch()

อยากให้ระบบนี้ทำงานให้ธุรกิจของคุณ?

เราสร้างและดูแลระบบแบบเดียวกันบนเว็บไซต์ธุรกิจจริง 16 แห่งของเราเอง เล่าเรื่องธุรกิจของคุณให้เราฟัง เราตอบกลับภายใน 24 ชั่วโมง