遇到 teamai-cli 报权限或鉴权失败,先别急着重装或换密钥。这类报错通常落在两个完全不同的层面:一层是进程没能把配置文件读进内存(文件系统层面的 EACCES、ENOENT),另一层是配置文件读到了、但里面的密钥或 token 没有被服务端接受(HTTP 401/403、invalid key)。两者要修的地方不一样,混着改只会让问题更难复现。判断顺序建议是:先看报错原文和完整堆栈,再确认实际加载了哪个配置文件,然后核对文件权限与属主,接着确认密钥是否真的进了进程环境,最后用一条最小命令逐项复测。
多数 teamai-cli 权限报错可以按“读取失败”和“鉴权失败”两类分流:出现 EACCES、permission denied、no such file 的,属于文件系统层,查路径与权限位;出现 401、403、invalid api key、unauthorized 的,属于鉴权层,查密钥内容与生效来源。判断依据应来自完整堆栈和实际加载的配置路径,而不是靠猜。下面每步只改一处、立即复测,涉及密钥时避免在终端回显明文。
先在报错原文里区分是读取失败还是鉴权失败
两类报错的关键词特征比较容易分开:读取失败通常伴随 EACCES、EPERM、permission denied、ENOENT、no such file or directory、cannot open config 等,且多数发生在进程启动早期、还没有发出网络请求;鉴权失败则通常伴随 401、403、Unauthorized、invalid api key、token expired、authentication failed,出现在日志里能看出已经连接到了服务端。看到 permission denied 就去查文件权限,看到 401 却去 chmod,方向就错了。
调高日志级别的常见做法是加 -v / -vv / `--verbose` / `--debug`,或设置环境变量(例如 TEAMAI_LOG_LEVEL=debug、LOG_LEVEL=debug)。具体开关名请以 teamai-cli `--help` 及各子命令的 `--help` 输出为准,不同版本的参数可能不一致。完整堆栈通常在标准错误流里,建议同时保留两份输出:
teamai-cli <子命令> `--debug` 1>out.log 2>err.log
# 或者直接合并查看
teamai-cli <子命令> `--debug` 2>&1 | tee run.log
重点看堆栈最上面几行里出现的是 open/read 类调用,还是 HTTP 请求类调用,这基本就定性了。
打印实际加载的配置文件路径,而不是假定路径
很多“密钥明明改了却没生效”的情况,是工具读的根本不是你改的那个文件。常见用来打印生效路径的方式有 teamai-cli config path、teamai-cli config list、teamai-cli `--print-config`、teamai-cli doctor 之类,具体命令名同样以实际帮助输出为准。如果工具没有这类子命令,就用调试日志里打印的配置加载行来确认。
多份配置并存时的优先级,通常是:命令行显式指定的 `--config` <file> 最高,其次是当前工作目录下的项目级配置,再次是用户主目录下的配置,最后是系统级配置。项目级配置经常被忽略——你在 ~/.config 改了密钥,但当前目录恰好有一份项目配置覆盖了它。可以先确认当前目录:
pwd
ls -la | grep -i teamai
ls -la ~/.config 2>/dev/null | grep -i teamai
核对文件权限与属主是否和当前运行用户一致
即使路径对了,读不到也可能是权限位或属主问题。先看这两组信息:
id -un # 当前运行用户
ls -l ~/.config/teamai/
stat -c '%A %U:%G %n' ~/.config/teamai/credentials 2>/dev/null
常见导致读取失败的权限位:文件属主是 root 而当前用户不是 root,且权限是 600 或 640;目录本身没有执行位(例如 700 且属主不是当前用户),导致无法进入或遍历;密钥文件是符号链接,指向一个当前用户不可读的目标;文件放在权限受限的挂载点上。注意 600 对密钥文件是合理的,问题往往出在属主上,而不是“权限太严”。修正示例(把路径和用户名替换成实际的):
chown "$USER" ~/.config/teamai/credentials
chmod 600 ~/.config/teamai/credentials
chmod 700 ~/.config/teamai
如果团队策略要求属主为 root,那就不要改属主,改成把当前用户加入对应用户组并调整组权限,或者改用环境变量方式注入,需要结合环境确认哪种更符合规范。
确认密钥是通过环境变量进入进程的
“这个终端能用,换个窗口就失效”基本是变量只导在当前 shell 会话,没写进 shell 配置。检查时不要用会回显明文的方式,下面几种只判断存在与长度:
[ -n "$TEAMAI_API_KEY" ] && echo set || echo unset
printenv TEAMAI_API_KEY >/dev/null && echo set || echo unset
echo "${#TEAMAI_API_KEY}" # 只看长度,不打印内容
要长期生效,把导出语句写进对应 shell 的启动文件,例如 ~/.bashrc、~/.zshrc 或 ~/.profile:
export TEAMAI_API_KEY="替换成你的密钥"
注意登录 shell 与非登录 shell 加载的文件可能不同,图形终端、IDE、systemd 服务、容器、定时任务默认都不会继承你交互式 shell 里的变量。这些场景下需要显式配置,例如服务单元里的 Environment=、容器启动参数 -e,或从受权限保护的环境文件读取。另外要确认环境变量与配置文件同时存在时的优先级,工具一般有明确定义,最好用实际生效值去验证,而不是假设谁覆盖谁。
改一处验一处,用最小命令复测
一次同时改路径、权限、环境变量,失败时无法判断是哪一项真正起作用。建议每改一项就复测一次,用不依赖复杂业务逻辑的最小命令:
teamai-cli <最轻量的子命令,例如 whoami / config path> `--debug`
预期输出是命令正常返回并显示出当前身份或生效配置路径,日志里不再出现 EACCES 或 401。如果仍然失败,下一步按顺序看三样东西:一是 err.log 堆栈的第一行调用位置,判断卡在读文件还是发请求;二是上一节打印出的实际生效配置路径,确认改的文件就是被读的文件;三是进程真实拿到的环境,/proc/<pid>/environ 可以查看仍在运行的进程环境。在 Linux 上还可以用 strace -f -e trace=openat teamai-cli ... 2>&1 | grep -i teamai 观察打开了哪些路径(需要相应权限)。确认清楚是哪一层的问题之后,再决定改配置还是换密钥,比反复卸载重装更快定位。