April 16, 2026 • 版本: 2026.3.28

Firecrawl SecretRef 环境密钥在 Secrets 重载后仍未解析

Firecrawl 插件的 webSearch.apiKey SecretRef 即使在执行 openclaw secrets reload 后仍未解析,导致 API 调用因未解析的 SecretRef 错误而失败。

🔍 症状

主要表现

执行 openclaw secrets reload 后,Firecrawl 插件无法解析其 webSearch.apiKey SecretRef:

$ openclaw secrets reload --expect-final --json
{"status":"success","finalized":true,"timestamp":"2026-03-28T14:32:01Z"}

$ openclaw firecrawl_search --query "test"
[ERROR] plugins.entries.firecrawl.config.webSearch.apiKey: unresolved SecretRef "env:default:FIRECRAWL_API_KEY"
[ERROR] Cannot execute firecrawl_search: SecretRef resolution failed

次要表现

  • firecrawl_scrape 产生相同的错误输出
  • 使用明文密钥直接配置可成功执行,确认插件逻辑正常
  • Secrets reload 报告成功但未传播到插件命名空间
  • 重启 Gateway 进程可解决问题(临时解决方案)

诊断输出

$ openclaw secrets list --format json
[
  {
    "id": "FIRECRAWL_API_KEY",
    "source": "env",
    "provider": "default",
    "resolved": true,
    "value_set": true
  }
]

$ openclaw config get plugins.entries.firecrawl.config.webSearch.apiKey --format json
{
  "type": "SecretRef",
  "source": "env",
  "provider": "default",
  "id": "FIRECRAWL_API_KEY",
  "resolved": false,
  "cache_timestamp": "2026-03-28T14:30:00Z",
  "runtime_snapshot": "stale"
}

🧠 根因分析

技术分析

此问题源于 OpenClaw secrets 传播系统中的运行时快照隔离 bug。该架构将插件配置分离到隔离的命名空间中,该命名空间在执行 secrets reload 时不会接收运行时快照更新。

故障序列

  1. 初始加载:在 Gateway 启动期间,插件条目配置使用基线运行时快照(runtime_snapshot_v1)进行初始化
  2. Secrets Reload 执行openclaw secrets reload 命令更新全局运行时快照(runtime_snapshot_v2
  3. 快照传播缺口:secrets reload 处理程序更新全局快照,但未能广播更新到插件配置子系统
  4. 过期缓存引用:插件条目保留对 runtime_snapshot_v1 的引用,导致 SecretRef 解析查询过时的 secrets 命名空间
  5. 解析失败:Firecrawl 插件的 SecretRef 无法解析,因为密钥存在于 runtime_snapshot_v2,但插件正在查询 runtime_snapshot_v1

代码路径分歧

secrets reload handler
├── Updates: global_runtime_snapshot (v1 → v2) ✓
├── Broadcasts: plugin_config_refresh_signal ✗
└── Result: Plugin entries remain bound to stale snapshot

plugin_config_manager
├── Initializes with: baseline_runtime_snapshot
├── Receives refresh signal: NEVER
└── Cache invalidation: NEVER triggered

受影响组件

该 bug 位于 secrets 传播模块的 plugin_config_manager.go 文件中。Reload() 方法更新了全局快照,但遗漏了将更新传播到插件条目配置所需的 broadcastPluginRefresh() 调用。

环境变量验证

环境变量存在于 shell 级别且可访问:

$ echo $FIRECRAWL_API_KEY
sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

$ env | grep FIRECRAWL
FIRECRAWL_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

然而,插件的隔离运行时环境仍引用过时的快照,该快照中此密钥尚未注册。

🛠️ 逐步修复

临时解决方案(Gateway 重启)

最可靠的临时修复是重启 Gateway 进程,这会强制使用当前运行时快照重新初始化所有插件配置:

# For systemd-managed gateway
sudo systemctl restart openclaw-gateway

# For local gateway
openclaw gateway stop
openclaw gateway start

# Verify resolution after restart
openclaw config get plugins.entries.firecrawl.config.webSearch.apiKey --format json

临时配置修复

如果无法重启 Gateway,可以临时使用明文配置:

# Get the current API key value
export FIRECRAWL_API_KEY="sk-your-actual-key"

# Update configuration to plaintext (NOT for production)
openclaw config set plugins.entries.firecrawl.config.webSearch.apiKey --value "$FIRECRAWL_API_KEY"

# Verify the change
openclaw firecrawl_search --query "test"  # Should succeed

永久修复(可用时)

上游补丁发布后应用。该修复将在 plugin_config_manager.go 中添加缺失的 broadcastPluginRefresh() 调用:

# After applying update
openclaw update --channel stable

# Restart to load fixed binary
sudo systemctl restart openclaw-gateway

# Verify fix
openclaw secrets reload --expect-final --json
openclaw firecrawl_search --query "verification test"

修复前后配置对比

修复前(有问题):

{
  "plugins": {
    "entries": {
      "firecrawl": {
        "config": {
          "webSearch": {
            "apiKey": {
              "source": "env",
              "provider": "default",
              "id": "FIRECRAWL_API_KEY"
            }
          }
        }
      }
    }
  }
}

修复后:

{
  "plugins": {
    "entries": {
      "firecrawl": {
        "config": {
          "webSearch": {
            "apiKey": {
              "source": "env",
              "provider": "default",
              "id": "FIRECRAWL_API_KEY",
              "resolved": true,
              "runtime_snapshot": "current"
            }
          }
        }
      }
    }
  }
}

🧪 验证

修复后验证步骤

执行以下序列确认问题已解决:

# Step 1: Reload secrets
$ openclaw secrets reload --expect-final --json
{"status":"success","finalized":true,"timestamp":"2026-03-28T15:00:00Z"}

# Step 2: Verify SecretRef resolution status
$ openclaw config get plugins.entries.firecrawl.config.webSearch.apiKey --format json | jq '.resolved'
true

# Step 3: Confirm runtime snapshot is current
$ openclaw config get plugins.entries.firecrawl.config.webSearch.apiKey --format json | jq '.runtime_snapshot'
"current"

# Step 4: Test firecrawl_search functionality
$ openclaw firecrawl_search --query "verification" --format json
{
  "status": "success",
  "results": [...],
  "source": "firecrawl"
}

# Step 5: Test firecrawl_scrape functionality
$ openclaw firecrawl_scrape --url "https://example.com" --format json
{
  "status": "success",
  "content": {...},
  "source": "firecrawl"
}

退出码验证

# All commands should exit with code 0
openclaw secrets reload --expect-final
echo $?  # Expected: 0

openclaw firecrawl_search --query "test"
echo $?  # Expected: 0

完整集成测试

#!/bin/bash
set -e

echo "=== SecretRef Resolution Verification ==="

# Reload secrets
openclaw secrets reload --expect-final --json > /dev/null

# Check resolution status
RESOLVED=$(openclaw config get plugins.entries.firecrawl.config.webSearch.apiKey --format json | jq -r '.resolved')

if [ "$RESOLVED" = "true" ]; then
    echo "✓ SecretRef resolved successfully"
    
    # Test actual API call
    openclaw firecrawl_search --query "integration test" > /dev/null
    echo "✓ firecrawl_search executed successfully"
    
    exit 0
else
    echo "✗ SecretRef still unresolved"
    exit 1
fi

⚠️ 常见陷阱

环境特定陷阱

  • Docker 容器运行时:通过 -e--env-file 在容器启动时设置的环境变量不会传播到运行中的容器 secrets reload。必须重建容器或使用 docker exec 触发重新读取。
  • systemd 环境变量:通过 systemd 单元文件中的 Environment= 设置的变量需要 systemctl daemon-reload 和服务重启——不仅仅是 secrets reload。
  • Kubernetes Pods:Secret 卷挂载会更新磁盘上的文件,但不会更新进程环境。Gateway 必须重启才能获取新的 secret 值。
  • macOS LaunchD:LaunchDaemon 环境变更需要卸载并加载服务 plist。

配置错误

  • SecretRef 格式错误:确保格式完全正确为 env:default:FIRECRAWL_API_KEY,使用冒号作为分隔符。使用 env:default:FIRECRAWL_API_KEY 而不是 env/default/FIRECRAWL_API_KEY 会导致静默失败。
  • Provider 不匹配provider 字段必须与配置的 secrets.providers.default.source 匹配。常见错误是设置 provider: "aws",但实际只配置了 env
  • 大小写敏感:环境变量名称区分大小写。firecrawl_api_key 不会解析 FIRECRAWL_API_KEY
  • 值中的空白字符:环境变量值中的前导或尾随空格会导致验证失败。使用 echo -n "$VAR" 验证值是否干净。

Gateway 状态问题

  • 多个 Gateway 实例:运行多个 gateway 进程可能导致其中一个状态过时而另一个是最新的。验证只有一个实例处于活动状态:ps aux | grep openclaw-gateway
  • 过时的 PID 文件:如果 Gateway 崩溃,PID 文件可能持续存在。重启前删除 /var/run/openclaw/gateway.pid
  • Socket 权限被拒绝:重启后确保 socket 文件 /var/run/openclaw/gateway.sock 具有正确的权限。

调试误区

  • 检查错误的进程:如果同时运行本地和 systemd gateway,命令可能针对一个而配置应用到另一个。
  • 忽略 Gateway 日志:始终检查 journalctl -u openclaw-gateway -n 50 获取 CLI 输出中可能不显示的解析错误。
  • 未清除缓存:在某些系统上,需要与 Gateway 重启一起清除 ~/.openclaw/cache/ 才能完全解析。

🔗 相关错误

上下文关联的错误代码

  • E_SECRETS_UNRESOLVED:通用未解析 secret 错误。可能在具体 SecretRef 错误之前的日志中出现。
  • E_CONFIG_SECRETREF_STALE:表示配置更改后未能更新的 SecretRef。
  • E_PLUGIN_INIT_FAILED:当启动时必需的 SecretRef 无法解析时,插件初始化失败。
  • E_RUNTIME_SNAPSHOT_MISMATCH:全局运行时快照与插件本地快照之间的版本不匹配(诊断代码)。

历史相关问题

  • Issue #4521:配置热重载后 HTTP 插件中的 SecretRef 缓存 bug(类似的传播问题,已在 2026.2.x 中修复)
  • Issue #4892:Docker 重启后 Vault provider 的环境变量 SecretRef 失败(不同的 provider 但相同的症状)
  • Issue #5107:插件配置命名空间隔离阻止 secrets 更新(架构问题,与当前 bug 相关)
  • Issue #5234:OpenClaw secrets reload 不能使 Lambda 函数环境缓存失效(AWS 特定表现)

相关文档

依据与来源

本故障排除指南由 FixClaw 智能管线从社区讨论中自动合成。