hook ของ Claude Code ไม่ทำงานบน Windows: สาเหตุและวิธีแก้
hook ตัวเดียวกันที่รันได้ดีบน Mac กลับไม่ทำอะไรเลยบน Windows หรือแย่กว่านั้นคือบล็อกทุกคำสั่ง แทบทุกครั้งสาเหตุคือเชลล์ นี่คือวิธีที่ Claude Code รัน hook บน Windows และวิธีทำให้ hook ของคุณเชื่อถือได้
คำตอบสั้น ๆ
บน Windows Claude Code จะรัน command ของ hook ด้วย Git Bash หรือด้วย PowerShell เมื่อไม่ได้ติดตั้ง Git Bash ระบุให้ชัดว่าต้องการตัวไหนด้วย "shell": "powershell" หรือ "shell": "bash" ให้ stdout มีแค่ออบเจ็กต์ JSON เดียว (ไม่มีข้อความ echo จากโปรไฟล์) ใช้รหัสออก 2 เพื่อบล็อก และอัปเดต Claude Code (บั๊ก hook บน Windows หลายตัวได้รับการแก้ไขในเวอร์ชันจนถึง 2.1.310) ดีบักด้วย /hooks และ claude --debug
เชลล์ไหนรัน hook ของคุณ
Claude Code ส่งสตริง command ให้เชลล์: sh -c บน macOS และ Linux, Git Bash บน Windows หรือ PowerShell เมื่อไม่ได้ติดตั้ง Git Bash ประโยคเดียวนี้จากเอกสารอ้างอิง hook อธิบายรายงาน “ใช้ได้บน Mac ของฉัน” ได้เกือบทั้งหมด คำสั่งที่เขียนสำหรับ PowerShell จะล้มเหลวใน Git Bash สคริปต์ bash จะล้มเหลวใน PowerShell และคุณจะได้ตัวไหนก็ขึ้นอยู่กับว่าบังเอิญติดตั้ง Git for Windows ไว้หรือไม่
เลิกเดาด้วยฟิลด์ shell ซึ่งรับค่า "bash" หรือ "powershell":
หากคุณต้องการใช้ Git Bash แต่ Claude Code หาไม่เจอ ให้ติดตั้ง Git for Windows หรือตั้ง CLAUDE_CODE_GIT_BASH_PATH เป็นตำแหน่งของมัน แล้วเริ่มเซสชันใหม่
อาการและสาเหตุ
| สิ่งที่คุณเห็น | สาเหตุที่น่าจะเป็น | วิธีแก้ |
|---|---|---|
| hook ดูเหมือนไม่เคยรันเลย | Claude Code เวอร์ชันเก่า, event หรือ matcher ผิด, JSON ในการตั้งค่าไม่ถูกต้อง | อัปเดต ตรวจ /hooks ลบคอมเมนต์และคอมมาต่อท้ายออก |
ParserError หรือ “unexpected token” | ไวยากรณ์ PowerShell ไปถึง Git Bash หรือกลับกัน | ตั้ง shell ให้ชัดเจน |
| เอาต์พุตของ hook “does not start with {” | มีบางอย่างพิมพ์ออกมาก่อน JSON ซึ่งมักมาจากโปรไฟล์ของเชลล์ | ปิดเอาต์พุตของโปรไฟล์ ส่งล็อกไปที่ stderr |
หาพาธที่ผสม \ กับ / ไม่เจอ | ตัวแปรพาธแบบ Windows ถูกต่อด้วยส่วนท้ายแบบ Unix | ใช้รูปแบบ exec: ใส่โปรแกรมใน command และแต่ละอาร์กิวเมนต์ใน args |
powershell: Permission denied จาก Git Bash | มีรายงานว่าเกิดเป็นครั้งคราวใน 2.1.283 และ 2.1.304–2.1.305 (#103910 ยังเปิดอยู่) | ใช้ "shell": "powershell" เพื่อไม่ต้องผ่าน Git Bash |
| hook ป้องกันปล่อยทุกอย่างผ่าน | รหัสออก 1 แทนที่จะเป็น 2 หรือบั๊ก fail-open ในเวอร์ชันเก่า | ออกด้วยรหัส 2 เพื่อบล็อก อัปเดตเป็น 2.1.310 ขึ้นไป |
| hook จบการทำงานทันทีโดยไม่มีเอาต์พุต | โปรแกรมแบบ GUI subsystem ที่เชลล์ไม่รอ | ใช้โปรแกรมคอนโซล หรือรอให้โปรเซสจบ |
มีแค่ JSON บน stdout
Claude Code อ่านเอาต์พุตมาตรฐานของ hook เป็นคำตอบ กฎในเอกสารสั้นมาก: อย่าพิมพ์อะไรไปที่ stdout นอกจากออบเจ็กต์ JSON บน Windows กฎนี้พังได้แบบแนบเนียน: Git Bash และบางการตั้งค่ายังคง source โปรไฟล์เชลล์ของคุณ และ echo ที่ไม่มีเงื่อนไขในโปรไฟล์นั้นจะถูกแปะไว้หน้า JSON ของคุณ hook จึง “ใช้ได้” ในเทอร์มินัล แต่ล้มเหลวภายใน Claude Code
ให้เขียนล็อกลงไฟล์หรือ stderr แทน และให้เอาต์พุตของโปรไฟล์แสดงเฉพาะเมื่อเป็นเชลล์แบบโต้ตอบ
รหัสออก: 2 บล็อก แต่ 1 ไม่บล็อก
รหัสออก 0 คือสำเร็จ รหัสออก 2 คือข้อผิดพลาดแบบบล็อก: ใน event ที่บล็อกได้ Claude Code จะหยุดการกระทำนั้นและแสดง stderr ของคุณ รหัสออก 1 โดยไม่มี JSON ที่ถูกต้องเป็นข้อผิดพลาดแบบไม่บล็อก และการกระทำจะดำเนินต่อไป หาก hook ของคุณบังคับใช้นโยบาย ให้ใช้รหัสออก 2
ไม่ใช่ทุก event ที่บล็อกด้วยวิธีนี้ได้ รหัสออกของ hook Notification จะถูกละเว้น hook Stop ที่ออกด้วยรหัส 2 จะทำให้ Claude ทำงานต่อ ส่วน hook PermissionRequest ละเว้นรหัสออก 2 ไปเลย และตัดสินผ่านออบเจ็กต์ decision ใน JSON แทน
Claude Code 2.1.309 แก้ปัญหา hook ของ PowerShell ไม่บล็อกเมื่อโปรแกรมของ hook ออกด้วยรหัส 2 หาก hook ป้องกันที่เขียนด้วย PowerShell ดูเหมือนถูกเพิกเฉย ให้ตรวจเวอร์ชันก่อน
การแก้ไขบน Windows ที่คุ้มค่าแก่การอัปเดต
changelog ของ Anthropic มีการแก้ไข hook บน Windows ต่อเนื่องยาว ตัวที่อธิบายกระทู้ในฟอรัมเก่า ๆ ได้คือ:
| เวอร์ชัน | การแก้ไข |
|---|---|
| 2.1.47 | hook PreToolUse และ PostToolUse ล้มเหลวแบบเงียบ ๆ บน Windows ตอนนี้รันด้วย Git Bash แทน cmd.exe |
| 2.1.161 | hook ที่เรียก bash โดยตรง (/usr/bin/bash script.sh) ล้มเหลวด้วย “command not found” |
| 2.1.299 | hook PreToolUse และ PermissionRequest ที่ไม่ได้ตั้ง shell จะ fail open เมื่อไม่มี Git for Windows ตอนนี้ hook ป้องกันที่ล้มเหลวจะบล็อก |
| 2.1.309 | hook ของ PowerShell ไม่บล็อกเมื่อรหัสออกเป็น 2 และ hook ป้องกันที่ใช้ "shell": "powershell" จะ fail open เมื่อไม่มี Git for Windows |
| 2.1.310 | hook ป้องกันที่คำสั่งเป็นแค่สตริงในเครื่องหมายคำพูด (เช่น พาธที่ใส่เครื่องหมายคำพูด) จะ fail open เมื่อไม่มี Git Bash |
issue เก่าที่ชื่อ “No hook is working on Windows” (#10450) ถูกรายงานในเวอร์ชัน 2.0.27 ผู้แสดงความคิดเห็นคนหนึ่งสืบพบว่าสาเหตุคือ stdin ไปไม่ถึงคำสั่งของ hook หากคุณใช้เวอร์ชันเก่าขนาดนั้น ให้อัปเดตก่อนดีบักอย่างอื่น
เรียกโปรแกรมโดยตรง
หาก hook ของคุณเป็นโปรแกรมที่คอมไพล์แล้ว คุณข้ามเชลล์ได้ด้วยรูปแบบ exec (ฟิลด์ args โดย shell จะถูกละเว้นเมื่อตั้ง args) บน Windows รูปแบบ exec กำหนดให้ command ต้องชี้ไปที่ไฟล์ปฏิบัติการจริง เช่น .exe ส่วน shim แบบ .cmd และ .bat (รวมถึงสิ่งที่ npm ติดตั้งเกือบทั้งหมด) จะสั่งรันโดยไม่มีเชลล์ไม่ได้ ให้ชี้ไปที่ .exe หรือใช้รูปแบบเชลล์
บทเรียนหนึ่งจากการสร้างตัวช่วย hook ของเราเอง: บน Windows โปรแกรมที่สร้างสำหรับ GUI subsystem จะไม่ถูกรอเมื่อเชลล์สั่งรัน เชลล์ไปต่อทันทีโดยไม่รอ เอเจนต์อ่านได้เอาต์พุตว่าง และ hook ดูเหมือนไม่ทำงาน โปรแกรม hook ต้องเป็นโปรแกรมคอนโซล
hook ของปลั๊กอินและพาธ
hook ของปลั๊กอินที่สร้างพาธอย่าง ${CLAUDE_PLUGIN_ROOT}/hooks/run.sh พังบน Windows ระหว่าง v2.1.2 ถึง v2.1.12 (#18610): ตัวแปรขยายเป็นพาธแบบแบ็กสแลช และการต่อส่วนท้ายแบบสแลชทำให้ได้พาธผสมที่ bash หาไม่เจอ เอกสารปัจจุบันให้วิธีแก้ที่สะอาด: ใช้รูปแบบ exec ทุกครั้งที่ hook อ้างถึงตัวแทนพาธ ใส่โปรแกรมใน command และแต่ละอาร์กิวเมนต์ใน args เช่น "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js"] แต่ละองค์ประกอบจะถูกส่งเป็นหนึ่งอาร์กิวเมนต์ โดยไม่มีเชลล์มาทำให้เพี้ยน
เช็กลิสต์การดีบัก
/hooksเปิดรายการแบบอ่านอย่างเดียวของทุก hook ที่กำหนดค่าไว้และแหล่งที่มาclaude --debug(หรือ/debugระหว่างเซสชัน) แสดงการรัน hook แต่ละครั้ง เอาต์พุต และรหัสออกclaude --debug-file <path>จะเขียนข้อมูลนี้ลงไฟล์- ตรวจสอบ JSON ไฟล์การตั้งค่าเป็น JSON แบบเคร่งครัด คอมมาต่อท้ายตัวเดียวทำให้ทั้งไฟล์ใช้ไม่ได้
- ตรวจ matcher matcher แยกตัวพิมพ์เล็กใหญ่
"*",""หรือการไม่ใส่ matcher จะตรงกับทุกอย่าง - รันคำสั่งเอง ในเชลล์เดียวกับที่ Claude Code จะใช้ โดยส่ง JSON ตัวอย่างผ่านไปป์เข้าไป
- ดู timeout hook แบบคำสั่งมีค่าเริ่มต้น 600 วินาที hook ที่รอคนตอบต้องมีเวลาเผื่อขนาดนั้น
หากต้องการปิดทุก hook ระหว่างตรวจสอบ ให้ตั้ง "disableAllHooks": true
ถ้าคุณแค่ต้องการการแจ้งเตือนและการอนุมัติ
การตั้งค่า hook บน Windows หลายแบบมีขึ้นด้วยเหตุผลเดียว: เพื่อให้รู้ว่า Claude Code ต้องการคุณเมื่อไร และตอบกลับได้ Pet Island ทำสิ่งนั้นได้โดยไม่ต้องเขียนสคริปต์ มันเชื่อมต่อกับ Claude Code ในคลิกเดียว จัดการรายละเอียดของ Windows ให้คุณ และนำทุกคำขอสิทธิ์ คำถาม และแผนมาไว้บนเกาะเล็ก ๆ ที่ด้านบนของหน้าจอ พร้อมคำสั่งหรือ diff ให้คุณกดอนุญาตหรือปฏิเสธ และยังใช้ได้เมื่อ Claude Code รันภายใน WSL
คำถามที่พบบ่อย
เชลล์ไหนรัน hook ของ Claude Code บน Windows?
Git Bash หรือ PowerShell เมื่อไม่ได้ติดตั้ง Git Bash ตั้ง "shell": "powershell" หรือ "shell": "bash" ใน hook เพื่อเลือกให้ชัดเจน
ทำไม hook ของ Claude Code ถึงทำงานในเทอร์มินัลแต่ไม่ทำงานใน Claude Code?
ส่วนใหญ่เป็นเพราะเอาต์พุตส่วนเกิน: โปรไฟล์เชลล์ที่ echo ข้อความจะถูกแปะไว้หน้า JSON ของ hook ให้พิมพ์แค่ออบเจ็กต์ JSON ไปที่ stdout
จะทำให้ hook บล็อกการเรียกเครื่องมือได้อย่างไร?
ออกด้วยรหัส 2 (หรือคืนค่าการตัดสินใจแบบ deny ใน JSON) รหัสออก 1 เป็นข้อผิดพลาดแบบไม่บล็อก และการกระทำจะดำเนินต่อไป hook PermissionRequest ละเว้นรหัสออก 2 และใช้ออบเจ็กต์ decision แทน
คำสั่งของ hook เป็นไฟล์ .cmd หรือ .bat ได้ไหม?
ไม่ได้ในรูปแบบ exec บน Windows ต้องชี้ไปที่ไฟล์ปฏิบัติการจริง เช่น .exe ใช้รูปแบบเชลล์เพื่อรันไฟล์ .cmd หรือ .bat
จะดูได้อย่างไรว่าทำไม hook ถึงล้มเหลว?
รัน claude --debug หรือพิมพ์ /debug และใช้ /hooks เพื่อดูว่ามี hook ไหนถูกโหลดบ้าง
แหล่งข้อมูล
การตั้งค่าและพฤติกรรมทุกอย่างในหน้านี้ได้รับการตรวจสอบกับหน้าเหล่านี้เมื่อวันที่ 26 ตุลาคม 2026 เอเจนต์เปลี่ยนแปลงเร็ว หากมีอะไรไม่ตรงกันแล้ว ให้ยึดหน้าทางการเป็นหลัก
- เอกสาร Claude Code: Hooks reference
- เอกสาร Claude Code: Hooks guide
- Claude Code: CHANGELOG
- Issue #10450: No hook is working on Windows
- Issue #18610: Plugin hooks cannot execute scripts on Windows
- Issue #103910: Hooks intermittently fail to spawn powershell (Git Bash)