air 报 failed to build, error: exit status 2 通常因 Go 代码编译失败,应先运行 go build 排查语法或 import 循环错误;确保 go.mod 在当前目录,且 .air.toml 中 [watch] 和 [build] 的 include_ext 一致;注意路径权限、inotify 限制及 HTTP keep-alive 干扰。

Go 本身不支持热重载,air 是靠杀进程 + go build + 启动新进程模拟出来的“热重载”,它对学习者很友好,但配置稍有偏差就会卡住、不重启、报错无声——问题几乎全出在路径、监听范围和构建命令三者的对齐上。
air 启动就报 failed to build, error: exit status 2 怎么办
这不是 air 坏了,90% 是你的 Go 代码根本编译不过。别急着改 .air.toml,先在终端执行 go build:
- 如果输出
undefined: xxx或import cycle not allowed,说明语法或模块引用有问题,得先修代码 - 如果
go build成功,再跑air才有意义 - 特别注意:
go.mod必须在当前工作目录下,否则air找不到模块根路径,go build也会失败
改了 config.yaml 或 templates/*.html 为啥不重启
air 默认只监听 .go 文件,其他后缀必须手动加进两个地方:
-
[watch]节里写include_ext = ["go", "yaml", "yml", "html", "tmpl"] -
[build]节里也得写一模一样的include_ext,漏掉任意一个都不触发构建 - Linux 下 inotify 句柄有限(默认 8192),加太多后缀容易触发
inotify limit reached,宁可少加,别堆一堆 - 如果只是改模板文案,更推荐程序内用
fsnotify监听 reload,而不是靠air杀进程——避免 HTTP 连接中断、状态丢失
fork/exec ./tmp/main: permission denied 在 macOS/Linux 上怎么解
这是最典型的权限+路径不一致问题:
立即学习“go语言免费学习笔记(深入)”;
-
build.cmd输出路径(比如go build -o ./tmp/main .)和build.bin(比如"./tmp/main")必须完全一致,多一个点、少一个斜杠都报错 - 某些 NFS 或容器挂载会 strip 执行权限,解决办法是在
build.cmd末尾加&& chmod +x ./tmp/main - 确保
./tmp目录有写权限;macOS 上若用 VS Code “原子保存”,建议设delay = 1000,防止读到半截文件
多个子命令目录(如 cmd/api/、cmd/cli/)怎么指定入口
air 默认在当前目录找 main.go,但你项目结构可能是 cmd/api/main.go + internal/,这时要显式指定:
- 在
[build]节写cmd = "go build -o ./tmp/api ./cmd/api",同时bin = "./tmp/api" - 别用
go run cmd/api/main.go—— 它不校验 import 循环,也捕获不到编译期错误,热重载意义不大 - 确认
go.mod已require本地模块(如./internal),否则go build会报找不到包
最容易被忽略的是:HTTP keep-alive 会让浏览器复用旧连接,看起来“改了代码却没生效”。测试时优先用 curl -H "Connection: close" http://localhost:8080,而不是刷新浏览器。


















