解决ChatTTS API调用失败:Permission Denied错误的全方位指南
第一次跑通 ChatTTS 的 demo 时,我满脑子都是“终于可以把文字秒变语音了”。结果一调用 API,终端啪地甩给我一行红字:
chattts api 调用失败: [errno 13] permission denied: 'c:\\users\\admin\\appdata\\local\\temp\\chattts_cache'当时一脸懵:代码是官网抄的,Python 环境是新的,怎么就“权限”了?折腾了两小时才搞明白,原来不是代码写错,而是“操作系统不让写”。这篇笔记把踩过的坑一次性打包,给同样刚入门的小伙伴一个“逃生路线”。
1. 错误背景:什么时候会撞见 errno 13
ChatTTS 为了提速,默认会把模型切片缓存到本地临时目录。只要下面三种场景出现任意一种,就会触发 Permission Denied:
- 缓存目录(或自定义目录)被管理员设为“只读”
- Python 进程不是目录所有者(例如装在系统盘,普通用户无写权限)
- 杀毒软件/公司 IT 策略把未知进程写盘行为拦截
一句话:操作系统“守门员”觉得你不该往那写,于是 Python 抛 errno 13。
2. 根本原因:把“谁”、“写什么”、“写到哪”拆开看
2.1 文件权限位(Linux)或 ACL(Windows)
- Linux 用
ls -ld 目录看 rwx,缺 w 就会写失败 - Windows 看“属性→安全→编辑”,如果当前用户没有“写入”勾,就会 13
2.2 进程身份
- 在 Linux 上
ps -o user= -p PID能看到脚本跑在谁的名下 - Windows 任务管理器“详细信息”页签看“用户名”
2.3 目标路径
- 默认缓存路径在
%LOCALAPPDATA%\\Temp(Win)或/tmp(Linux) - 若公司把 Temp 映射到网络盘,而网络盘只读,也会 13
3. 分步解决方案:Win / Linux 双平台演示
下面以“把缓存换到用户有权限的目录”为核心思路,同时给出“直接改权限”两种做法,按自己环境挑一条即可。
3.0 前置检查:先确认报错目录
运行一次脚本,把报错里那串绝对路径复制下来,下文统称<cache_dir>。
3.1 方案 A:换目录(最干净,推荐新手)
在用户目录新建缓存父目录
Windows PowerShell:mkdir $env:USERPROFILE\chattts_my_cacheLinux / macOS:
mkdir -p ~/chattts_my_cache在 Python 代码里手动指定缓存路径
官方 SDK 支持cache_dir参数,样例如下:from chattts import ChatTTS import os # 1. 选一个自己一定写得进的地方 my_cache = os.path.expanduser("~/chattts_my_cache") # Linux/mac # my_cache = os.path.expandvars(r"%USERPROFILE%\chattts_my_cache") # Win # 2. 初始化时把目录塞进去 tts = ChatTTS(cache_dir=my_cache) # 3. 常规调用 wav = tts.infer("你好,世界") tts.save(wav, "hello.wav")验证
跑完脚本后,如果目录里出现.pt、.json等缓存文件,且没有再报 errno 13,说明成功。
3.2 方案 B:直接给旧目录加写权限(适合无法改代码的场景)
Windows:
- 资源管理器定位到
c:\users\admin\appdata\local\temp - 右键→属性→安全→编辑→选中当前登录用户→勾“完全控制”→应用
Linux:
sudo chmod 1777 /tmp # 所有人可写,带粘滞位,最安全 # 或者只给自己 sudo chown $USER:$USER /tmp/chattts_cache -R chmod u+rwx /tmp/chattts_cache -R3.3 方案 C:临时用管理员/sudo 跑(不推荐长期)
Windows:在“开始”里搜 PowerShell→右键“以管理员身份运行”
Linux:sudo python3 demo.py
注意:一旦换普通用户还会再报错,CI 环境里慎用。
4. 权限管理最佳实践:写一次,省十次
项目根目录下放一个
cache文件夹,并把它写进.gitignore
好处:克隆仓库的同事也能秒级复现路径,不会误传到仓库用
pathlib.Path.mkdir(parents=True, exist_ok=True)自动建目录,
再os.access(dir, os.W_OK)做运行时断言,早失败早提醒在
README.md里加一句:若遇 Permission Denied,请给
cache目录写权限或设置环境变量CHATTTS_CACHE=/your/dir容器化部署时,Dockerfile 里提前创建同名卷并
RUN chmod 777 /app/cache
防止 Kubernetes 随机用户 UID 导致写失败
5. 常见陷阱 & 调试技巧
- 路径拼错大小写:Windows 不敏感,Linux 敏感,复制报错要看清
- 中文用户名:Win 下有时
%USERPROFILE%含中文,没毛病;但老版本 Python 在expandvars时可能转码失败,统一用pathlib最稳 - 杀毒软件秒删:把
chattts_my_cache加入白名单,否则文件刚落地就被锁 - 多进程并发:如果开多线程/多卡,记得给缓存目录加文件锁,官方已用
filelock库,升级 SDK 即可 - 网络盘缓存:Samba/NFS 默认无执行权限,
.pt文件会被当成病毒模板拦截,最好缓存到本地 SSD
快速调试三板斧:
手动写文件验证
import os test_file = os.path.join(my_cache, 'can_write.tmp') open(test_file, 'w').close() # 如果这里也 13,就是目录权限问题看进程身份
Linux:id
Win:whoami看文件属性
Linux:namei -l 长路径能把每一级权限列出来
Win:icacls 目录一次看清 ACL
6. 把“修 bug”变成“防 bug”:项目里怎么提前规避
- 在
requirements.txt里锁定chattts>=0.2.1,新版默认带filelock并自动回退到用户目录 - 写个
setup.py或Makefile目标,自动检测cache是否可写,不可写就弹提示并退出 1 - 把缓存路径做成环境变量,CI 里统一挂载到
/tmpfs内存盘,提速又免权限 - 定期清理:缓存文件动辄几百 MB,写个
cron/ 计划任务,一周清一次,防止磁盘爆
7. 小结
Permission Denied 不是代码 bug,而是“操作系统守门员”提醒:你写的位置不对,或者身份不够。新手阶段最怕把红字当成天书,其实三步就能解决:
- 看清报错路径
- 确认自己有没有写权限
- 要么给权限,要么换目录
把这三步固化到项目脚本里,以后换电脑、换服务器、换容器,都能一次跑通。下次再看到errno 13,你就能像老司机一样,嘴角一翘:哦,又是权限小老弟,两分钟搞定。
祝你语音合成一路畅通,不再被“Permission Denied”打断灵感!