OpenClaw gateway start 报 401 Invalid API key?一个环境变量的坑

今天折腾了半小时,终于搞明白为什么 openclaw gateway start 一直报 HTTP 401: Invalid API key,而 openclaw gateway run 却能正常工作。

记录一下,免得以后又踩。


问题现象

openclaw gateway run 前台运行,一切正常,能正常对话。

但换成 openclaw gateway start(systemd 后台服务),就报错:

HTTP 401: Invalid API key 

明明配置文件里 API key 写得好好的,为什么会这样?


原因分析

runstart 的区别:

  • run — 前台运行,直接继承当前 shell 的环境变量
  • start — 通过 systemd 启动后台服务,环境变量是隔离的

问题就出在这里。

我的 shell 里设置了:

exportANTHROPIC_BASE_URL=https://api.aigocode.com exportANTHROPIC_AUTH_TOKEN=sk-xxx... 

gateway run 能继承这些变量,所以能用。但 systemd service 启动时,这些变量根本不存在。

虽然 openclaw.json 配置文件里也写了 apiKey,但 OpenClaw 优先读取环境变量。环境变量不存在时,可能走了默认的 Anthropic 官方 API,然后用配置文件里的 key 去请求——当然会 401。


解决方案

把环境变量加到 systemd service 文件里。

Step 1:找到 service 文件

cat ~/.config/systemd/user/openclaw-gateway.service 

Step 2:在 [Service] section 添加环境变量

[Service] # ... 其他配置 ... Environment=ANTHROPIC_BASE_URL=https://api.aigocode.com Environment=ANTHROPIC_AUTH_TOKEN=sk-你的key [Install] WantedBy=default.target 

⚠️ 注意:Environment 必须放在 [Service] section 里,不能放在 [Install] 后面,否则 systemd 会直接忽略。

Step 3:重新加载并重启

systemctl --user daemon-reload systemctl --user restart openclaw-gateway 

搞定。


踩坑记录

我一开始用 >> 追加环境变量到文件末尾,结果加到了 [Install] section 后面。systemd 日志里有这么一行:

Unknown key name 'Environment' in section 'Install', ignoring. 

直接被忽略了,难怪不生效。


写在最后

这个问题的本质是:前台运行和后台服务的环境变量是隔离的

如果你用的是第三方 API 代理(比如 aigocode),或者自定义了 ANTHROPIC_BASE_URL,记得把这些变量也加到 systemd service 里。

希望这篇文章能帮到遇到同样问题的人。

Read more

C++ 入门全指南:从发展史到第一个程序,命名空间 + 输入输出手把手讲

C++ 入门全指南:从发展史到第一个程序,命名空间 + 输入输出手把手讲

目录 一、C++的发展历史 1.发展历史 2.C++的版本更新 3.C++的参考文档 二、C++的学习建议 1.C++的应用领域: 2.学习书籍推荐: 三、C++的第一个程序 四、命名空间 1.namespace的价值: 2.namespace的定义: 1)使用namespace来命名空间,以及使用命名空间(详解见注释): 2)命名空间的嵌套使用 3)多文件定义的命名空间问题 3.namespace命名空间的使用: 1)指定命名空间访问 2)using将命名空间中某个成员展开 3)展开命名空间中全部成员 五、C++输入&输出

By Ne0inhk

C++ 函数与成员函数声明机制的深度剖析与演进全景报告

C++ 函数与成员函数声明机制的深度剖析与演进全景报告 1. 核心综述:声明作为接口契约的基石 在 C++ 编程语言的庞大语义体系中,函数声明(Function Declaration)不仅是连接调用方与实现方的接口契约,更是编译器执行类型检查、重载决议(Overload Resolution)、符号链接(Linkage)以及代码生成的核心依据。与 C 语言相比,C++ 的函数声明引入了极其复杂的修饰符系统、模板推导机制、面向对象的成员语义以及现代 C++(C++11 至 C++23)所带来的编译期计算特性。这一演变过程将函数声明从简单的“代码跳转地址标签”提升为一种描述计算行为、约束条件和类型关系的元数据集合。 函数声明本质上引入了一个标识符(Identifier),该标识符指定了一个函数实体,并可选地指定其参数类型列表(即原型,Prototype)。值得注意的是,声明与定义(Definition)在 C++ 中有着严格的区分:声明仅引入名称和类型,

By Ne0inhk
C++(二)类和对象上篇

C++(二)类和对象上篇

1. 类与对象的概念 C语言是面向过程(功能)的语言,注重解决问题的过程、步骤;C++是面向对象的语言,注重对象之间的关系及其交互,面向对象是比面向功能更高级的开发方式,像所熟知的Java,C#,python都是面向对象的语言;其实C++最早的别名是C with classes,主要做的改进就是加入类(class)和对象(object),将现实世界类和对象映射到虚拟计算机系统,比如我们在等待外卖的时候,可以看到地图上的骑手距我们还有多远,骑手是一类对象,用户是一类对象,一个类可以实例化出很多对象,注重对象之间的关系,如下图所示。 其实类的思想是封装,我们来看一下为什么要提出封装的概念;如下图所示,在C语言中变量和函数是分离的,我们提供了接口供使用者调用,但是对于取栈顶元素这个函数,有的人可能感觉就一句代码我直接就写了,还调什么函数啊,然后就出现了下面的代码,因为不知道top究竟是指向栈顶元素还是栈顶元素的下一个位置,不知道底层实现,在这里乱用,很危险。 intmain(){ ST st;STInit(&st);int

By Ne0inhk
从构造到操作:全面掌握 C++ std::vector 的接口使用

从构造到操作:全面掌握 C++ std::vector 的接口使用

一、vector的接口 vector是一个类模板,这也就意味着可以存储各种类型。vector底层是一个数组,一个顺序容器。 接下来就看看vector的接口。 1. 构造函数 //用n个val构造vector对象explicitvector(size_type n,const value_type& val =value_type(),const allocator_type& alloc =allocator_type());//用一段迭代器区间构造vector对象template<classInputIterator>vector(InputIterator first, InputIterator last,const allocator_type& alloc =allocator_type());//拷贝构造vector(const vector& x); 2. 赋值运算符重载

By Ne0inhk