air启动失败应先执行go build排查编译错误,再检查go.mod位置、build.bin与build.cmd路径一致、watch.cwd配置及fsnotify配置热加载。

air 启动失败先别改配置,先跑 go build
90% 的 air 启动失败不是配置错,而是代码本身编译不过。报 exit status 2 或 undefined: xxx 时,直接在终端执行 go build,看是否能过。只有确认 go.mod 在当前目录、所有 import 路径正确、没循环引用,再让 air 接管才有意义。
常见干扰项:
-
go.mod不在当前工作目录:air默认从含go.mod的目录启动,否则找不到模块根路径 - 编辑器保存延迟导致读到半截文件:别乱设
delay = 200,默认1000更稳 - 用了
//go:build约束但没同步更新build.cmd,导致关键文件被跳过
fork/exec ./tmp/main: permission denied 的真实原因
这是 macOS/Linux 上最典型的执行失败,根源不是权限位没设,而是 build.bin 和 build.cmd 输出路径不一致。比如 build.bin = "./tmp/main",但 build.cmd = "go build -o ./bin/main .",air 就会去执行不存在的 ./tmp/main。
必须保证两处路径严格相同:
-
build.bin和build.cmd都用正斜杠,例如./tmp/main - Windows 用户也别写
.\tmp\main,一律用./tmp/main - 确保
./tmp目录存在且可写(air不自动创建父目录)
改了 internal/handler/xxx.go 没反应?检查监听范围
air 默认只监听当前工作目录及子目录下的 .go 文件,不跨模块、不跟进符号链接、不扫描 vendor/ 或隐藏目录。如果你的项目结构是:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
project/ ├── go.mod ├── cmd/api/main.go └── internal/handler/user.go
却在 project/ 根目录运行 air,那 internal/ 下的改动不会触发重建——因为 main.go 在 cmd/api/,air 默认只从 main.go 所在目录向上找 go.mod,再向下监听。
解决办法:
- cd 到
cmd/api/目录下运行air - 或在
.air.toml中显式配置watch.cwd = "cmd/api" - 多
main项目(如cmd/api和cmd/worker)必须指定main_cmd = "go run cmd/api/main.go",否则默认找错位置
配置文件热加载别靠 air,用 fsnotify 自己监听
air 只适合代码变更重启,它不处理 config.yaml 这类非 Go 文件的运行时重载。想让配置生效,得自己用 github.com/fsnotify/fsnotify 监听:
- 只
watcher.Add("config.yaml"),别监听整个目录,避免编辑器临时文件(如.config.yaml.swp)误触发 - 在 goroutine 中阻塞读
watcher.Events,只响应fsnotify.Write和fsnotify.Chmod事件 - 收到事件后先
os.Stat确认文件存在且非空,再os.ReadFile - 每次解析都生成新结构体,用
atomic.Value原子替换指针,别直接改字段 - 解析失败必须保留旧配置并打 error 日志,不能 panic 或静默丢弃
真正麻烦的从来不是监听动作本身,而是 reload 时 DB 连接池、HTTP server、gRPC client 等组件是否真正切换到了新配置——这一步没法自动化,得每个模块自己实现 Reload() 接口。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










