#Chat in UI returns empty every time

1 messages Β· Page 1 of 1 (latest)

somber geyser
#

All chat paths (UI, openclaw agent, infer model run) close empty. Log: incomplete turn detected: stopReason=stop payloads=0. Raw stream emits only assistant_message_end, empty text/thinking, no stream_start. NODE_DEBUG=https: zero HTTP. OpenRouter Activity: zero gateway calls.
Env: OpenClaw 2026.4.15, npm -g, Node 24.15, Ubuntu 24.04, systemd user svc. doctor: 60 plugins, 0 errors.
Config: primary=openrouter/auto, fallbacks=[openrouter/openai/gpt-oss-120b:free], plugins.openrouter.enabled=true.
Auth: auth-profiles.json has openrouter:default with valid key (curl returns content). Same key at config.env.OPENROUTER_API_KEY and systemd Environment=.
models list: both entries Auth=yes, configured, alias:OpenRouter.
infer model run --model openrouter/auto --prompt hi: provider:openrouter model:openrouter/auto outputs:1, same error.
Tried: rewriting auth-profiles.json, config.env, systemd env, restart each.
Q: Auth=yes+configured, but dispatcher closes at payloads=0 with no stream_start or HTTP. Canonical 2026.4.x path for OpenRouter creds? Is infer model auth login --provider openrouter the right entry?

deep boltBOT
pastel gulchBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> βœ… Mark Solution

deep boltBOT
somber geyser
#

Hello, can you see my question?

midnight rootBOT
#

Let me verify the current docs/source paths, then I’ll give you the shortest safe fix.

#

Yep, I can see it.

Short answer:

  • The right command is openclaw models auth login --provider openrouter, not infer model auth ....
  • Canonical OpenRouter creds in 2026.4.x are still OPENROUTER_API_KEY, from the gateway process env, ~/.openclaw/.env, or the config env block. Docs: https://docs.openclaw.ai/providers/openrouter https://docs.openclaw.ai/help/environment https://docs.openclaw.ai/cli/models
  • Your symptom does not look like plain bad auth. That incomplete turn detected: stopReason=stop payloads=0 path is the runner’s β€œassistant ended with no visible text” fallback. If auth were the problem, I’d expect a provider/probe error, not a clean stop.
  • I also found later fixes for OpenRouter empty replies / reasoning_details parsing. On openrouter/auto, that can absolutely look like β€œempty turn every time”.

A few concrete notes:

  • plugins.openrouter.enabled=true is not needed, OpenRouter is bundled/enabled by default.
  • NODE_DEBUG=https is weak evidence here, a lot of this traffic is fetch/undici-based and may not show there.
  • If you have a custom OpenRouter base URL anywhere, the canonical one is https://openrouter.ai/api/v1.

What I’d try next, in order:

#
openclaw models status --probe --probe-provider openrouter
openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json
openclaw config get models.providers.openrouter

And honestly, I’d upgrade first. 2026.4.15 is old enough that I’d suspect you’re sitting right before one of those empty-turn/OpenRouter fixes.

If you paste:

  • openclaw models status --probe --probe-provider openrouter
  • openclaw config get models.providers.openrouter

I can narrow it down pretty fast.

somber geyser
#

openclaw-agent@automation:~$ openclaw models status --probe --probe-provider openrouter

🦞 OpenClaw 2026.4.15 (041266a) β€” I'm not magicβ€”I'm just extremely persistent with retries and coping strategies.

17:24:37 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
β”‚
17:25:39 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
17:25:39 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
17:25:39 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
17:25:39 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
17:25:39 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
17:25:41 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.

#

Config : ~/.openclaw/openclaw.json
Agent dir : ~/.openclaw/agents/main/agent
Default : openai/auto (from auto)
Fallbacks (1) : openai/gpt-oss-120b:free
Image model : -
Image fallbacks (0): -
Aliases (1) : OpenRouter -> openrouter/auto
Configured models (1): openrouter/auto

Auth overview
Auth store : ~/.openclaw/agents/main/agent/auth-profiles.json
Shell env : off
Providers w/ OAuth/tokens (0): -

  • openrouter effective=profiles:~/.openclaw/agents/main/agent/auth-profiles.json | profiles=1 (oauth=0, token=0, api_key=1) | openrouter:default=sk-or-v1...401d1a35 | env=sk-or-v1...401d1a35 | source=env: OPENROUTER_API_KEY
  • perplexity effective=env:sk-or-v1...401d1a35 | env=sk-or-v1...401d1a35 | source=env: OPENROUTER_API_KEY

Missing auth

  • openai Run openclaw models auth login --provider openai, openclaw configure, or set an API key env var.

OAuth/token status

  • none

Auth probes
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Model β”‚ Profile β”‚ Status β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ openrouter/openrouter/auto β”‚ openrouter:default (api_key) β”‚ ok Β· 41.9s β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Probed 1 target in 63s

#

openclaw-agent@automation:~$ openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json
17:26:48 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
17:26:48 [model-selection] Model "auto" specified without provider. Falling back to "openai/auto". Please use "openai/auto" in your config.
Error: Model override "openrouter/openai/gpt-oss-120b:free" is not allowed for agent "main".
openclaw-agent@automation:~$ openclaw config get models.providers.openrouter

🦞 OpenClaw 2026.4.15 (041266a) β€” I'm not AI-powered, I'm AI-possessed. Big difference.

Config path not found: models.providers.openrouter

midnight rootBOT
#

Fair catch, you’re right. I was looking at main / the unreleased changelog, not the latest stable tag. Sorry.

So, corrected take:

  • Yes, the canonical auth entry is openclaw models auth login --provider openrouter
  • No, infer model auth ... is not the right command path
  • But I still don’t think this is primarily a creds problem

Why I’m saying that:

  • Auth=yes + a valid profile + env key means discovery sees a usable credential source
  • stopReason=stop payloads=0 is the runner’s empty visible-output path
  • that smells more like stream parsing / runtime handling than β€œbad OpenRouter key”

The highest-signal next step is to separate openrouter/auto routing from OpenRouter auth:

#
openclaw models status --probe --probe-provider openrouter
openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json

How to read that:

  • if the probe fails, then auth/runtime resolution is still wrong somewhere
  • if the probe passes but the direct concrete model still returns empty, that’s very likely a stable bug
  • if the concrete model works but openrouter/auto stays empty, then it’s probably an auto route / stream-shape issue

Two extra checks I’d do after that:

openclaw config get models.providers.openrouter
openclaw config get auth.order
#

And if you ever set a custom base URL anywhere, make sure it is:

https://openrouter.ai/api/v1

If you paste the output of those 4 commands, I can probably tell pretty quickly whether this is config drift or a real 2026.4.15 bug. If it’s the latter, it should go to GitHub: https://github.com/openclaw/openclaw/issues

#

Aha, that warning is the smoking gun.

Model "auto" specified without provider. Falling back to "openai/auto" only happens when the effective config contains a bare auto somewhere. That is not an OpenRouter auth warning.

So at least for the agent/context you ran, OpenClaw is seeing:

model: "auto"

instead of:

model: "openrouter/auto"

That would also explain why OpenRouter never gets touched.

#

Most likely places:

  • agents.defaults.model.primary
  • a per-agent override in agents.list[].model
  • OPENCLAW_AGENT_DIR / PI_CODING_AGENT_DIR making models status inspect a different agent than the one you think

I’d check these next:

openclaw config get agents.defaults.model
openclaw config get agents.list
env | grep -E 'OPENCLAW_AGENT_DIR|PI_CODING_AGENT_DIR'
openclaw models status --probe --probe-provider openrouter --agent main

(If your real agent id is not main, use that instead.)

#

If any of those show just auto, that’s the bug. Set it back to openrouter/auto.

So, updated answer to your original question:

  • right auth command: openclaw models auth login --provider openrouter
  • but I would stop chasing auth for now, because this new output points much more strongly to a model-selection override / wrong agent context problem

If you paste the output of openclaw config get agents.defaults.model and openclaw config get agents.list, I think we can pin this down pretty quickly.

#

Nice, this finally makes it clear.

Your OpenRouter auth is fine. The probe proves that:

  • openrouter:default ... Status ok
  • source is OPENROUTER_API_KEY

The real problem is your effective model config is wrong:

  • Default : openai/auto (from auto)
  • Fallbacks : openai/gpt-oss-120b:free

So OpenClaw is not actually defaulting to openrouter/auto. It is seeing a bare auto, then coercing it to openai/auto.

That means the fix is model selection, not auth.

What to change

#

Your default model should be explicitly provider-qualified:

agents: {
  defaults: {
    model: {
      primary: "openrouter/auto",
      fallbacks: ["openrouter/openai/gpt-oss-120b:free"],
    },
  },
}

Easiest CLI fix

#
openclaw models set openrouter/auto
openclaw models fallbacks clear
openclaw models fallbacks add openrouter/openai/gpt-oss-120b:free

Then verify:

openclaw models status --probe --probe-provider openrouter

What you want to see after that is roughly:

Default       : openrouter/auto
#
Fallbacks (1) : openrouter/openai/gpt-oss-120b:free

Direct answer to your original auth question

  • correct auth command: openclaw models auth login --provider openrouter
  • but in your case, don’t spend more time on auth, because the auth probe already says it’s good

If you rerun models status after those 3 commands and paste the top β€œConfig / Default / Fallbacks” block, I can sanity-check it.

#

Yep, that matches the picture now.

models.providers.openrouter not existing is fine. It means you don’t have a custom provider block. The problem is elsewhere:

  1. your effective default model is still auto, which resolves to openai/auto
  2. your allowlist (agents.defaults.models) currently contains only openrouter/auto, so the fallback override is rejected

So this is now squarely a model config / allowlist issue, not auth.

Best fix, simplest while debugging

In ~/.openclaw/openclaw.json, make agents.defaults.model explicit, and either remove the allowlist entirely or include both models.

Recommended, remove allowlist for now

{
#
  agents: {
    defaults: {
      model: {
        primary: "openrouter/auto",
        fallbacks: ["openrouter/openai/gpt-oss-120b:free"],
      },
    },
  },
}

If you want to keep the allowlist

{
  agents: {
#
    defaults: {
      model: {
        primary: "openrouter/auto",
        fallbacks: ["openrouter/openai/gpt-oss-120b:free"],
      },
      models: {
        "openrouter/auto": { alias: "OpenRouter" },
        "openrouter/openai/gpt-oss-120b:free": {},
      },
    },
  },
}

Then restart the gateway:

#
openclaw gateway restart

Then re-check:

openclaw models status --probe --probe-provider openrouter
openclaw infer model run --model openrouter/auto --prompt hi --json

What I’d expect after the fix:

  • Default : openrouter/auto
  • Fallbacks (1) : openrouter/openai/gpt-oss-120b:free

So, short version: your OpenRouter key is good, your effective model config is not.

somber geyser
#

Config : ~/.openclaw/openclaw.json
Agent dir : ~/.openclaw/agents/main/agent
Default : openrouter/openrouter/auto (from openrouter/auto)
Fallbacks (1) : openrouter/openai/gpt-oss-120b:free
Image model : -
Image fallbacks (0): -
Aliases (1) : OpenRouter -> openrouter/auto
Configured models (2): openrouter/auto, openrouter/openai/gpt-oss-120b:free

Auth overview
Auth store : ~/.openclaw/agents/main/agent/auth-profiles.json
Shell env : off
Providers w/ OAuth/tokens (0): -

  • openrouter effective=profiles:~/.openclaw/agents/main/agent/auth-profiles.json | profiles=1 (oauth=0, token=0, api_key=1) | openrouter:default=sk-or-v1...401d1a35 | env=sk-or-v1...401d1a35 | source=env: OPENROUTER_API_KEY
  • perplexity effective=env:sk-or-v1...401d1a35 | env=sk-or-v1...401d1a35 | source=env: OPENROUTER_API_KEY

OAuth/token status

  • none

Auth probes
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Model β”‚ Profile β”‚ Status β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ openrouter/openrouter/auto β”‚ openrouter:default (api_key) β”‚ ok Β· 41.9s β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Probed 1 target in 62.1s

midnight rootBOT
#

Nice, this looks much better.

At this point:

  • auth is good
  • allowlist is good
  • model selection is now good

I would not chase creds anymore.

Also, openrouter/openrouter/auto in status is ugly, but I would treat that as a display/ref-format quirk, not the root problem. It’s basically provider=openrouter plus model id openrouter/auto.

So the next decisive test is just:

openclaw infer model run --model openrouter/auto --prompt hi --json
#
openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json

How I’d read it:

  • if auto fails but the concrete fallback works, pin the concrete model for now and call it an openrouter/auto bug
  • if both still fail empty, then you’ve basically proven this is a 2026.4.15 runtime/stream bug, not auth or config

If that second case happens, I’d file it here with the before/after config output you already gathered, because this is now a really solid repro: https://github.com/openclaw/openclaw/issues

If you paste those two infer model run results, I can help you write the exact issue text.

somber geyser
#

openclaw-agent@automation:~$ openclaw infer model run --model openrouter/auto --prompt hi --json
17:54:18 [agent/embedded] incomplete turn detected: runId=f30e511d-ab87-4cae-8efb-deacf717aabf sessionId=f30e511d-ab87-4cae-8efb-deacf717aabf stopReason=stop payloads=0 β€” surfacing error to user
{
"ok": true,
"capability": "model.run",
"transport": "local",
"provider": "openrouter",
"model": "openrouter/auto",
"attempts": [],
"outputs": [
{
"text": "⚠️ Agent couldn't generate a response. Please try again.",
"mediaUrl": null
}
]
}
openclaw-agent@automation:~$ openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json
17:56:41 [agent/embedded] incomplete turn detected: runId=f30e511d-ab87-4cae-8efb-deacf717aabf sessionId=f30e511d-ab87-4cae-8efb-deacf717aabf stopReason=stop payloads=0 β€” surfacing error to user
{
"ok": true,
"capability": "model.run",
"transport": "local",
"provider": "openrouter",
"model": "openai/gpt-oss-120b:free",
"attempts": [],
"outputs": [
{
"text": "⚠️ Agent couldn't generate a response. Please try again.",
"mediaUrl": null
}
]
}

midnight rootBOT
#

Yep, that’s enough evidence. This is not an auth problem anymore.

You’ve now shown all of these at once:

  • valid OPENROUTER_API_KEY
  • openclaw models status --probe --probe-provider openrouter = ok
  • effective model config fixed
  • explicit openrouter/auto and explicit concrete OpenRouter model both fail the same way
  • failure is the same empty embedded-turn path every time

So I’d stop digging local config and file a bug: https://github.com/openclaw/openclaw/issues

You can paste this:

Title: OpenRouter model.run returns empty incomplete turn with valid auth on 2026.4.15
#

### Summary

On OpenClaw 2026.4.15, OpenRouter-authenticated runs complete with:

`incomplete turn detected: stopReason=stop payloads=0`

No visible assistant output is produced. This happens in UI chat, `openclaw agent`, and `openclaw infer model run`.

### Environment

- OpenClaw: 2026.4.15
- Install: npm -g
- Node: 24.15
- OS: Ubuntu 24.04
#
- Gateway: systemd user service

### Auth state

OpenRouter auth appears healthy:

- `OPENROUTER_API_KEY` present in env
- same key in auth store
- `openclaw models status --probe --probe-provider openrouter` succeeds

Relevant probe output:

```text
Auth probes
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Model β”‚ Profile β”‚ Status β”‚
#

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ openrouter/openrouter/auto β”‚ openrouter:default (api_key) β”‚ ok Β· 41.9s β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜


### Effective config

```text
Default : openrouter/openrouter/auto (from openrouter/auto)
Fallbacks (1) : openrouter/openai/gpt-oss-120b:free
Configured models (2): openrouter/auto, openrouter/openai/gpt-oss-120b:free

No custom models.providers.openrouter block is configured.

Repro

#

```bash
openclaw infer model run --model openrouter/auto --prompt hi --json
openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json

Actual

Both commands return:

[agent/embedded] incomplete turn detected: ... stopReason=stop payloads=0

and the JSON output is:

#

```json
{
  "ok": true,
  "capability": "model.run",
  "transport": "local",
  "outputs": [
    {
      "text": "⚠️ Agent couldn't generate a response. Please try again.",
      "mediaUrl": null
    }
  ]
}
#
### Expected

A normal text response from the OpenRouter-backed model.

### Extra notes

Before fixing config, the default model had been accidentally resolving from bare `auto` to `openai/auto`, but that has been corrected and the problem still reproduces with explicit OpenRouter model refs.

This does not appear to be credential resolution, because the OpenRouter probe succeeds while actual embedded runs return empty final turns.

One small correction to your original auth question, for the record: the right auth command is openclaw models auth login --provider openrouter, but your probe already proved auth is working.

If you want, I can also help trim that into a shorter maintainer-friendly version.

somber geyser
#

trim that

midnight rootBOT
#

Yep, here’s a tighter version:

Title: OpenRouter runs return empty incomplete turns on 2026.4.15 despite successful auth probe

### Summary

On OpenClaw 2026.4.15, OpenRouter-backed runs return:

`incomplete turn detected: stopReason=stop payloads=0`

This happens in UI chat, `openclaw agent`, and `openclaw infer model run`.

### Environment

- OpenClaw 2026.4.15
#
- npm -g install
- Node 24.15
- Ubuntu 24.04
- systemd user service

### Auth / config

- `OPENROUTER_API_KEY` is set and valid
- `openclaw models status --probe --probe-provider openrouter` succeeds
- effective model config:
  - primary: `openrouter/auto`
  - fallback: `openrouter/openai/gpt-oss-120b:free`

### Repro

```bash
#

openclaw infer model run --model openrouter/auto --prompt hi --json
openclaw infer model run --model openrouter/openai/gpt-oss-120b:free --prompt hi --json


### Actual

Both commands log:

```text
[agent/embedded] incomplete turn detected: ... stopReason=stop payloads=0

and return:

{
  "ok": true,
#

"capability": "model.run",
"transport": "local",
"outputs": [
{
"text": "⚠️ Agent couldn't generate a response. Please try again.",
"mediaUrl": null
}
]
}


### Expected

Normal text output from the OpenRouter-backed model.

### Notes
#

OpenRouter auth appears healthy, so this looks like an embedded runner / streaming issue rather than credential resolution.

If you want, I can trim it one more step into a super-short β€œbug report only” version.

somber geyser
#

what should I do next? switch to a new primary model?

midnight rootBOT
#

Yeah, if you need to get unstuck now, switching primary is the pragmatic move, but only if you already have auth for another provider.

What I’d do next:

  1. Stop debugging OpenRouter config
    You’ve already narrowed it down enough. This looks like a stable bug.

  2. If you have another provider configured, switch to that as primary
    Good short-term workaround.
    If you don’t have other provider auth yet, switching primary alone won’t help.

  3. File the GitHub issue
    Use the trimmed report we just made: https://github.com/openclaw/openclaw/issues

  4. Optional, if you want to test the fix early
    Try current main / source install, since I found newer unreleased OpenRouter empty-reply fixes in the changelog.

#

So my recommendation is:

  • Need it working today? Switch to another authenticated provider.
  • Need OpenRouter specifically? File the bug, then either wait for a fix or test main.

If you want, I can help you pick the cleanest temporary fallback based on which provider creds you already have.

somber geyser
#
  1. I want to use Openai Codex plan. What's the best way to do it?
  2. explain this. Don't fully understand.
midnight rootBOT
#

Yep. For OpenAI Codex plan, the best path is:

2) Use OpenAI Codex plan

If you want the subscription / ChatGPT Codex route, use the openai-codex provider, not openai/*.

Easiest setup

openclaw onboard --auth-choice openai-codex

Or direct auth

openclaw models auth login --provider openai-codex
openclaw config set agents.defaults.model.primary openai-codex/gpt-5.4
openclaw models list --provider openai-codex
#

That uses your Codex / ChatGPT sign-in, not a separate OpenAI API key.

So if your goal is β€œjust get unstuck and move to Codex,” I’d do that next.

Docs: https://docs.openclaw.ai/providers/openai


4) What I meant by β€œtry current main / source install”

That was only about the OpenRouter bug.

  • stable release = v2026.4.15
  • current main = newer code on GitHub that has not been released yet

Why that matters:

  • sometimes a bug is fixed on main
#
  • the fix just hasn’t made it into the next stable release yet

So β€œtry main/source” means:

  • run OpenClaw from a Git checkout of the repo
  • use the latest code directly
  • see whether your OpenRouter issue is already fixed there

It’s basically a newer but less conservative path.

Recommendation

  • If you want Codex now, stay on stable and set up openai-codex
  • If you want to keep chasing the OpenRouter empty-turn bug, then trying main is a way to test whether upstream already fixed it

If you want, I can give you the smallest exact command sequence to switch from your current OpenRouter setup to openai-codex cleanly.

somber geyser
#

yes please

midnight rootBOT
#

Yep, smallest clean switch:

openclaw models auth login --provider openai-codex
openclaw models set openai-codex/gpt-5.4
openclaw models fallbacks clear
openclaw models list --provider openai-codex

What each does:

  1. logs OpenClaw into your Codex / ChatGPT subscription
  2. makes openai-codex/gpt-5.4 the default
  3. removes the broken OpenRouter fallback path for now
  4. verifies the Codex models are visible

A couple of notes:

#
  • this does not delete your OpenRouter setup, it just stops using it as the default
  • if you already have Codex CLI logged in, OpenClaw may reuse that login
  • if the change doesn’t show up right away, do:
openclaw gateway restart

If you want, after this I can give you the matching β€œswitch back to OpenRouter later” command sequence too.

somber geyser
#

openclaw-agent@automation:~$ openclaw models set openai-codex/gpt-5.4

Config overwrite: /home/openclaw-agent/.openclaw/openclaw.json (sha256 ca273c1fabde4a9a8440a3229787dca2c9998d7b1fb098ed81456ef097d3e236 -> 231c3e985eea2134723836afab609353218c429253430428b32cc9a9390589ef, backup=/home/openclaw-agent/.openclaw/openclaw.json.bak)
Updated ~/.openclaw/openclaw.json
Default model: openai-codex/gpt-5.4
openclaw-agent@automation:~$ openclaw models fallbacks clear

Config overwrite: /home/openclaw-agent/.openclaw/openclaw.json (sha256 231c3e985eea2134723836afab609353218c429253430428b32cc9a9390589ef -> 22a74ef6e4b7a4b187b459964693cac4a80e3306ff9fea7ba84b1aa11861cfc8, backup=/home/openclaw-agent/.openclaw/openclaw.json.bak)
Updated ~/.openclaw/openclaw.json
Fallback list cleared.
openclaw-agent@automation:~$ openclaw models list --provider openai-codex

Model Input Ctx Local Auth Tags
openai-codex/gpt-5.4 text+image 1025k no yes default,configured

midnight rootBOT
#

Nice, that looks healthy now.

You’ve got:

  • openai-codex/gpt-5.4 as default
  • fallbacks cleared
  • Codex auth present
  • model shows configured

So the next check is just:

openclaw infer model run --model openai-codex/gpt-5.4 --prompt hi --json

If that works, I’d do two more things:

#
openclaw gateway restart

Then start a fresh UI chat / new session. Some old sessions can keep stale model state.

So the flow now is:

  1. verify infer model run works on Codex
  2. restart gateway
  3. test in a fresh chat

If you paste that one infer model run result, I can tell you immediately whether you’re clear.

somber geyser
#

a side question: what is the difference between 'systemctl --user restart openclaw-gateway' and 'openclaw gateway restart'

openclaw-agent@automation:~$ openclaw gateway restart

Gateway service disabled.
Start with: openclaw gateway install
Start with: openclaw gateway
Start with: systemctl --user start openclaw-gateway.service
Start with: systemd user services are unavailable; install/enable systemd or run the gateway under your supervisor.
Start with: If you're in a container, run the gateway in the foreground instead of openclaw gateway.

midnight rootBOT
#

Short version:

  • systemctl --user restart openclaw-gateway.service = talks directly to systemd
  • openclaw gateway restart = OpenClaw’s wrapper command around the managed gateway service

On a normal Linux user-service install, they’re basically the same end result.

The difference is that openclaw gateway restart is smarter and more portable:

  • knows about OpenClaw’s managed install flow
  • works cross-platform (systemd / launchd / Windows task path)
  • gives nicer diagnostics if no managed service is installed

That’s exactly what happened here.

Your output means:

#

OpenClaw does not think you currently have an installed/enabled managed gateway service.

So for your setup right now, openclaw gateway restart has nothing managed to restart.

What that implies

You are probably in one of these states:

  1. running the gateway manually in a shell
  2. running it under some other supervisor/container
  3. systemd user services are not actually available in that environment

So what should you do?

Use the restart method that matches how the gateway was started:

  • if it was started with a systemd user unit, use:
#
  systemctl --user restart openclaw-gateway.service
  • if it was started manually, stop and start that foreground process
  • if it’s in a container/supervisor, restart it there

If you want to confirm which world you’re in, run:

openclaw gateway status
openclaw status

That should make it pretty obvious.

somber geyser
#

'Tip: Codex-capable models can use native Codex web search. Enable it with openclaw configure --section web (recommended mode: cached). Docs: https://docs.openclaw.ai/tools/web'

how do I see whic web search option I am using? during onboard, I entered a tavily API key.

midnight rootBOT
#

There are two different things here, which is why it’s confusing:

1) Managed web_search provider

This is where Tavily / Perplexity / Brave / etc. live.

Check it with:

openclaw config get tools.web.search
openclaw config get tools.web.search.provider
  • if provider is set, that’s the managed provider you’re using
  • if provider is unset, you’re in auto-detect

Important bit: in auto-detect mode, Perplexity via OPENROUTER_API_KEY is checked before Tavily.

#

So if you have both:

  • OPENROUTER_API_KEY
  • TAVILY_API_KEY

then managed web_search will likely pick Perplexity/OpenRouter, not Tavily, unless you explicitly pin Tavily.

2) Native Codex web search

That tip you pasted is about Codex-native web search, which is separate from Tavily.

Check that with:

openclaw config get tools.web.search.openaiCodex

If that is enabled, then while using openai-codex/*, OpenClaw can use native Codex web search instead of the normal managed web_search provider.

#

So what I’d run

openclaw config get tools.web.search
openclaw config get tools.web.search.openaiCodex

How to read it

  • provider: "tavily" β†’ you are pinned to Tavily
  • no provider + OPENROUTER_API_KEY present β†’ managed search probably resolves to Perplexity/OpenRouter
  • openaiCodex.enabled: true β†’ Codex-native search is on for Codex models

If you want Tavily specifically

#

The cleanest way is:

openclaw configure --section web

and explicitly choose Tavily.

So, short answer: entering a Tavily key during onboard does not necessarily mean Tavily is the active search provider, especially if OPENROUTER_API_KEY is also present and web search is still on auto-detect.

somber geyser
#

openclaw-agent@automation:~$ openclaw config get tools.web.search.provider

tavily
openclaw-agent@automation:~$ openclaw config get tools.web.search.openaiCodex

Config path not found: tools.web.search.openaiCodex

midnight rootBOT
#

Perfect, that answers it.

Right now you are using:

  • managed web search provider: tavily
  • native Codex web search: not configured / effectively off

So the tip you saw is not active yet in your setup.

What your output means

openclaw config get tools.web.search.provider
# tavily

That means normal web_search is pinned to Tavily.

#
openclaw config get tools.web.search.openaiCodex
# Config path not found

That means there is no explicit Codex-native web-search config block. In practice, I would read that as: you are not using native Codex web search right now.

So, current behavior

With your current config:

  • web_search => Tavily
  • Codex-native search => not enabled

If you want to enable native Codex web search

The clean way is:

#
openclaw configure --section web

and enable the OpenAI Codex web search option there.

Or set it in config like this:

{
  tools: {
    web: {
      search: {
        provider: "tavily",
        openaiCodex: {
          enabled: true,
#
          mode: "cached",
        },
      },
    },
  },
}

So the short answer is: you are on Tavily right now, not Codex-native search.

somber geyser
midnight rootBOT
#

Yep, do this:

openclaw config set plugins.entries.openai.config.personality off

That disables the OpenAI personality overlay for both:

  • openai/*
  • openai-codex/*

Then restart the gateway, using however your gateway is actually running.

If you want to verify it stuck:

somber geyser
#

How do I check what .md files will my OpenClaw read and in what order whenever it starts up, especially after a reboot.

midnight rootBOT
#

Short version: OpenClaw does not read every .md in your workspace. It only auto-injects a fixed set of bootstrap files.

What it reads by default

From the workspace root, in the normal bootstrap set:

  1. AGENTS.md
  2. SOUL.md
  3. TOOLS.md
  4. IDENTITY.md
  5. USER.md
  6. HEARTBEAT.md
  7. BOOTSTRAP.md (first-run only, brand-new workspace)
  8. MEMORY.md if present, or lowercase memory.md as fallback

A few important gotchas:

#
  • memory/YYYY-MM-DD.md files are not part of the normal bootstrap prompt
  • arbitrary .md files in subfolders are not auto-read
  • subagents only get AGENTS.md + TOOLS.md

Reboot-specific thing

If you mean gateway restart / machine reboot, there is one extra file to know:

  • BOOT.md = optional startup checklist that can run on gateway restart when internal hooks are enabled

So:

  • new session / normal run β†’ bootstrap files above
  • gateway restart β†’ BOOT.md may also matter

How to check what was actually injected

Best way:

#
/context detail

That shows the injected workspace files for the current session, including raw vs injected sizes and truncation.

Where to look on disk

Usually:

~/.openclaw/workspace

You can list the standard files with:

somber geyser
#

yes do that

midnight rootBOT
#

Yep, use this:

W="$(openclaw config get agent.workspace 2>/dev/null || printf '%s\n' "$HOME/.openclaw/workspace")"; for f in AGENTS.md SOUL.md TOOLS.md IDENTITY.md USER.md HEARTBEAT.md BOOT.md BOOTSTRAP.md MEMORY.md memory.md; do [ -f "$W/$f" ] && printf '%s\n' "$W/$f"; done

That prints the startup-relevant markdown files from your current workspace in the order you’d care about.

Two notes:

  • BOOT.md is the restart/reboot-specific one
  • BOOTSTRAP.md is first-run only

If you want the actual files injected into a live session, the best check is still:

#
/context detail

That’s the ground truth after a reboot + fresh session.

somber geyser
#

How do I correctly address these issues:

Security audit
Summary: 1 critical Β· 4 warn Β· 1 info
CRITICAL Telegram group commands have no sender allowlist
Telegram group access is enabled but no sender allowlist is configured; this allows any group member to invoke /… commands (including skill commands).
Fix: Approve yourself via pairing (recommended), or set channels.telegram.groupAllowFrom (or per-group groups.<id>.allowFrom).
WARN No auth rate limiting configured
gateway.bind is not loopback but no gateway.auth.rateLimit is configured. Without rate limiting, brute-force auth attacks are not mitigated.
Fix: Set gateway.auth.rateLimit (e.g. { maxAttempts: 10, windowMs: 60000, lockoutMs: 300000 }).
WARN Some gateway.nodes.denyCommands entries are ineffective
gateway.nodes.denyCommands uses exact node command-name matching only (for example system.run), not shell-text filtering inside a command payload. - Unknown …
Fix: Use exact command names (for example: canvas.present, canvas.hide, canvas.navigate, canvas.eval, canvas.snapshot, canvas.a2ui.push, canvas.a2ui.pushJSONL, canvas.a2ui.reset). If you need broader restrictions, remove risky command IDs from allowCommands/default workflows and tighten tools.exec policy.

#

WARN Potential multi-user setup detected (personal-assistant model warning)
Heuristic signals indicate this gateway may be reachable by multiple users: - channels.discord.groupPolicy="allowlist" with configured group targets Runtime/pr…
Fix: If users may be mutually untrusted, split trust boundaries (separate gateways + credentials, ideally separate OS users/hosts). If you intentionally run shared-user access, set agents.defaults.sandbox.mode="all", keep tools.fs.workspaceOnly=true, deny runtime/fs/web tools unless required, and keep personal/private identities + credentials off that runtime.
WARN Discord slash commands have no allowlists
Discord slash commands are enabled, but neither an owner allowFrom list nor any per-guild/channel users allowlist is configured; /… commands will be rejected f…
Fix: Add your user id to channels.discord.allowFrom (or approve yourself via pairing), or configure channels.discord.guilds.<id>.users.

midnight rootBOT
#

Yep, here’s the clean way to fix each one.

1) CRITICAL: Telegram group commands have no sender allowlist

For Telegram, the durable fix is to use numeric Telegram user IDs in config.

Best one-owner pattern

Set your Telegram user ID in channels.telegram.allowFrom, then allow the group(s) under channels.telegram.groups.

{
  channels: {
    telegram: {
      enabled: true,
      dmPolicy: "allowlist",
      allowFrom: ["8734062810"],
#

      groups: {
        "-1001234567890": {
          requireMention: true,
        },
      },
    },
  },
}

That is usually enough, because for Telegram:

  • groupAllowFrom falls back to config allowFrom when unset
  • pairing is DM-only
  • do not put group chat IDs in groupAllowFrom
#

If you want to restrict group triggers to specific people inside a group, use either:

channels.telegram.groupAllowFrom: ["8734062810"]

or per-group:

channels.telegram.groups["-1001234567890"].allowFrom: ["8734062810"]

2) WARN: No auth rate limiting configured

Add this:

#
{
  gateway: {
    auth: {
      rateLimit: {
        maxAttempts: 10,
        windowMs: 60000,
        lockoutMs: 300000,
      },
    },
  },
}

That’s the exact shape the audit is asking for.

3) WARN: gateway.nodes.denyCommands entries are ineffective

#

This warning means your deny list probably contains things like:

  • wildcards: system.*
  • pattern-ish names
  • shell text you hoped would be matched inside payloads

That does not work.

gateway.nodes.denyCommands only matches exact node command IDs.

Good examples

{
  gateway: {
    nodes: {
      denyCommands: [
#
        "system.run",
        "system.run.prepare",
        "canvas.present",
        "canvas.hide",
        "canvas.navigate",
        "canvas.eval",
        "canvas.snapshot",
        "canvas.a2ui.push",
        "canvas.a2ui.pushJSONL",
        "canvas.a2ui.reset",
      ],
    },
  },
}
#

If your goal is broader lockdown, the right move is:

  • remove risky entries from gateway.nodes.allowCommands
  • tighten tools.exec policy
  • don’t rely on pattern matching in denyCommands

4) After editing config

Restart the gateway, then rerun:

openclaw security audit

One important correction

The audit text saying β€œapprove yourself via pairing” is a bit easy to overread. For Telegram group auth, pairing alone is not the durable fix. Group sender auth is based on config allowlists like:

#

These two are a bit different:

1) WARN Potential multi-user setup detected

This one is mostly a trust-model warning, not β€œyou are broken”.

The audit is warning because a Discord bot in guild channels can look like a shared-user surface, even if you only intend to use it yourself.

If this is really just for you

Lock it down so only your Discord user ID can trigger it:

{
  session: {
    dmScope: "per-channel-peer",
  },
#

  channels: {
    discord: {
      groupPolicy: "allowlist",
      allowFrom: ["123456789012345678"],

      guilds: {
        "1456350064065904867": {
          users: ["123456789012345678"],
          channels: {
            "1495713305325600848": { allow: true, requireMention: true },
          },
        },
      },
    },
#
  },

  commands: {
    ownerAllowFrom: ["discord:123456789012345678"],
  },

  tools: {
    fs: { workspaceOnly: true },
  },

  agents: {
    defaults: {
      sandbox: { mode: "all" },
    },
  },
#
}

You do not need every one of those knobs just to function, but they’re the hardening moves the audit is pointing at.

If multiple people really will use it

Then the audit is right, and the best fix is:

  • separate gateways
  • separate credentials
  • ideally separate OS users / hosts

OpenClaw is fundamentally a personal assistant trust model.

2) WARN Discord slash commands have no allowlists

#

This one is more concrete.

For Discord slash commands, give OpenClaw an explicit allowlist.

Minimum useful fix

For DMs and self-use:

{
  channels: {
    discord: {
      allowFrom: ["123456789012345678"],
    },
  },

  commands: {
#
    ownerAllowFrom: ["discord:123456789012345678"],
  },
}

If you want slash commands in a guild too

Add your user ID under that guild:

{
  channels: {
    discord: {
      groupPolicy: "allowlist",
      guilds: {
        "1456350064065904867": {
#
          users: ["123456789012345678"],
          channels: {
            "1495713305325600848": { allow: true, requireMention: true },
          },
        },
      },
    },
  },
}

Practical read on these warnings

  • multi-user setup = advisory / trust warning
  • Discord slash commands have no allowlists = real config gap, easy to fix
somber geyser
#

Why is it every time I use the 'openclaw' command in cli, it starts up so slowly? And is there a way for me to disable the feature where it outputs '🦞 OpenClaw 2026.4.15 (041266a) β€” I'm the middleware between your ambition and your attention span.' every time?

midnight rootBOT
#

Yep, both are configurable.

Why openclaw can feel slow on every CLI run

A fresh CLI invocation has startup overhead, and two things the docs call out are:

  • Node module compile/startup cost
  • OpenClaw’s self-respawn path

The supported tuning is:

grep -q 'NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache' ~/.bashrc || cat >> ~/.bashrc <<'EOF'
export NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache
mkdir -p /var/tmp/openclaw-compile-cache
export OPENCLAW_NO_RESPAWN=1
#
EOF
source ~/.bashrc

That does two things:

  • NODE_COMPILE_CACHE speeds up repeated CLI runs
  • OPENCLAW_NO_RESPAWN=1 avoids extra startup overhead from self-respawn

First run warms the cache, later runs are the ones that benefit most.

Disable the funny tagline

That exact line is the CLI banner tagline.

Hide just the tagline, keep version line

somber geyser
#

OpenClaw security audit
Summary: 2 critical Β· 1 warn Β· 1 info
Run deeper: openclaw security audit --deep

CRITICAL
fs.config.perms_writable Config file is writable by others
/home/openclaw-agent/.openclaw/openclaw.json mode=664; another user could change gateway/auth/tool policies.
Fix: chmod 600 /home/openclaw-agent/.openclaw/openclaw.json
channels.telegram.groups.allowFrom.missing Telegram group commands have no sender allowlist
Telegram group access is enabled but no sender allowlist is configured; this allows any group member to invoke /… commands (including skill commands).
Fix: Approve yourself via pairing (recommended), or set channels.telegram.groupAllowFrom (or per-group groups.<id>.allowFrom).

WARN
security.trust_model.multi_user_heuristic Potential multi-user setup detected (personal-assistant model warning)
Heuristic signals indicate this gateway may be reachable by multiple users:

  • channels.telegram.groupPolicy="allowlist" with configured group targets
    Runtime/process tools are exposed without full sandboxing in at least one context.
    Potential high-impact tool exposure contexts:
  • agents.defaults (sandbox=non-main; runtime=[exec, process]; fs=[read, write, edit, apply_patch]; fs.workspaceOnly=false)
    OpenClaw's default security model is personal-assistant (one trusted operator boundary), not hostile multi-tenant isolation on one shared gateway.
    Fix: If users may be mutually untrusted, split trust boundaries (separate gateways + credentials, ideally separate OS users/hosts). If you intentionally run shared-user access, set agents.defaults.sandbox.mode="all", keep tools.fs.workspaceOnly=true, deny runtime/fs/web tools unless required, and keep personal/private identities + credentials off that runtime.
#

INFO
summary.attack_surface Attack surface summary
groups: open=0, allowlist=2
tools.elevated: enabled
hooks.webhooks: disabled
hooks.internal: enabled
browser control: enabled
trust model: personal assistant (one trusted operator boundary), not hostile multi-tenant on one shared gateway

midnight rootBOT
#

You’ve got 3 real things to fix here:

1) openclaw.json is group-writable

That one is straightforward:

chmod 600 /home/openclaw-agent/.openclaw/openclaw.json

Or let OpenClaw fix perms for you:

openclaw security audit --fix

2) Telegram group commands have no sender allowlist

This is the important one.

#

For a single-owner bot, the clean pattern is:

{
  channels: {
    telegram: {
      allowFrom: ["8734062810"],

      groups: {
        "-1001234567890": {
          requireMention: true,
        },
      },
    },
  },
}
#

A few gotchas:

  • allowFrom / groupAllowFrom should be Telegram user IDs
  • groups should contain the negative Telegram group/supergroup chat IDs
  • do not put group IDs in groupAllowFrom
  • pairing is DM-only, so don’t rely on pairing alone for group auth

If only specific people inside the group should be allowed, then add:

channels.telegram.groupAllowFrom: ["8734062810"]

or per group:

#
channels.telegram.groups["-1001234567890"].allowFrom: ["8734062810"]

3) Multi-user trust-model warning

This one is basically saying:

you have Telegram group ingress + powerful tools + not-full sandboxing

And that’s true from your audit output:

  • sandbox=non-main
  • runtime tools exposed: exec, process
  • fs tools exposed: read, write, edit, apply_patch
  • fs.workspaceOnly=false

If this is really only for you

#

Then I’d at least harden it to:

{
  agents: {
    defaults: {
      sandbox: { mode: "all" },
    },
  },
  tools: {
    fs: { workspaceOnly: true },
  },
}

And if you do not need shell/file-editing from Telegram groups, restrict those too.

#

If multiple people can trigger it

Then the warning is justified. Best practice is still:

  • separate gateways
  • separate credentials
  • ideally separate OS users/hosts

Practical order I’d do this in

  1. chmod 600 /home/openclaw-agent/.openclaw/openclaw.json
  2. fix Telegram allowFrom / groups
  3. set sandbox.mode="all"
  4. set tools.fs.workspaceOnly=true
  5. rerun:
#

That INFO block is basically just a security posture summary, not a new failure.

What it means

  • groups: open=0, allowlist=2
    Good, no fully open groups. You have 2 allowlisted group surfaces.

  • tools.elevated: enabled
    Higher risk. Elevated mode can escape normal sandbox boundaries, so keep its allowlists very tight.

  • browser control: enabled
    Browser automation is available, so that’s another powerful surface if an untrusted user can reach it.

  • hooks.webhooks: disabled
    Good, no webhook ingress path.

  • hooks.internal: enabled

#

Fine, that’s normal for internal automation / bootstrap-style behavior.

  • trust model: personal assistant ... not hostile multi-tenant
    This is the big framing reminder: OpenClaw assumes one trusted operator boundary, not a shared hostile-user environment.

Practical interpretation

If this gateway is really just for you, this summary is mostly fine.

If other people can trigger it through Telegram/Discord groups, then the combination of:

  • allowlisted groups
  • tools.elevated: enabled
  • browser control enabled

means the audit’s earlier warning is fair. In that case I’d either:

#
  1. split into separate gateways, or
  2. harden it a lot more:
    • agents.defaults.sandbox.mode: "all"
    • tools.fs.workspaceOnly: true
    • restrict/disable elevated where not needed
    • keep group sender allowlists very tight

So, short version: this INFO block is not a problem by itself, it’s just confirming your gateway still has some powerful surfaces exposed and is not designed as a multi-tenant shared bot.

Security docs: https://docs.openclaw.ai/gateway/security

somber geyser
#

OpenClaw security audit
Summary: 1 critical Β· 1 warn Β· 1 info
Run deeper: openclaw security audit --deep
Fix: openclaw security audit --fix

FIX
skip chmod 700 ~/.openclaw (already)
chmod 600 ~/.openclaw/openclaw.json
skip chmod 700 ~/.openclaw/credentials (missing)
skip chmod 700 ~/.openclaw/agents/main (already)
skip chmod 700 ~/.openclaw/agents/main/agent (already)
skip chmod 600 ~/.openclaw/agents/main/agent/auth-profiles.json (already)
chmod 700 ~/.openclaw/agents/main/sessions
skip chmod 600 ~/.openclaw/agents/main/sessions/sessions.json (already)
chmod 600 ~/.openclaw/agents/main/sessions/4a450f2f-7e89-4243-b6bb-75d3904f3951.jsonl
chmod 600 ~/.openclaw/agents/main/sessions/probe-openrouter-01035917-8d22-4688-aa2f-58b74d223ab6.jsonl
chmod 600 ~/.openclaw/agents/main/sessions/probe-openrouter-1bdc1a22-fc04-44cd-956d-ee3ee9544ca2.jsonl
chmod 600 ~/.openclaw/agents/main/sessions/probe-openrouter-3678fc50-cbfe-4ea3-be12-518c4f85536d.jsonl
chmod 600 ~/.openclaw/agents/main/sessions/probe-openrouter-8bbd7452-47ac-4d2b-aabb-14663a42aacb.jsonl
chmod 600 ~/.openclaw/agents/main/sessions/probe-openrouter-96e806d3-7b5d-41f8-9bef-efaff2e6e40c.jsonl

#

CRITICAL
channels.telegram.groups.allowFrom.missing Telegram group commands have no sender allowlist
Telegram group access is enabled but no sender allowlist is configured; this allows any group member to invoke /… commands (including skill commands).
Fix: Approve yourself via pairing (recommended), or set channels.telegram.groupAllowFrom (or per-group groups.<id>.allowFrom).

WARN
security.trust_model.multi_user_heuristic Potential multi-user setup detected (personal-assistant model warning)
Heuristic signals indicate this gateway may be reachable by multiple users:

  • channels.telegram.groupPolicy="allowlist" with configured group targets
    Runtime/process tools are exposed without full sandboxing in at least one context.
    Potential high-impact tool exposure contexts:
  • agents.defaults (sandbox=non-main; runtime=[exec, process]; fs=[read, write, edit, apply_patch]; fs.workspaceOnly=false)
    OpenClaw's default security model is personal-assistant (one trusted operator boundary), not hostile multi-tenant isolation on one shared gateway.
    Fix: If users may be mutually untrusted, split trust boundaries (separate gateways + credentials, ideally separate OS users/hosts). If you intentionally run shared-user access, set agents.defaults.sandbox.mode="all", keep tools.fs.workspaceOnly=true, deny runtime/fs/web tools unless required, and keep personal/private identities + credentials off that runtime.

INFO
summary.attack_surface Attack surface summary
groups: open=0, allowlist=2
tools.elevated: enabled
hooks.webhooks: disabled
hooks.internal: enabled
browser control: enabled
trust model: personal assistant (one trusted operator boundary), not hostile multi-tenant on one shared gateway

midnight rootBOT
#

Nice, that part worked.

What openclaw security audit --fix just cleaned up was the filesystem permissions side:

  • ~/.openclaw/openclaw.json β†’ fixed to 600
  • ~/.openclaw/agents/main/sessions β†’ fixed to 700
  • session .jsonl files β†’ fixed to 600

So the old β€œconfig file is writable by others” issue should now be gone.

A couple of notes on that output

  • skip chmod 700 ~/.openclaw (already) = good
  • skip chmod 700 ~/.openclaw/credentials (missing) = not a problem, it just doesn’t exist right now
  • the probe-openrouter-...jsonl files are just your probe session transcripts getting locked down properly

What’s probably still left

#

Since the summary is still:

  • 1 critical
  • 1 warn
  • 1 info

that usually means the remaining items are the ones --fix doesn’t solve automatically, like:

  • Telegram group sender allowlist
  • multi-user/trust-model warning

So at this point, the next useful check is just:

openclaw security audit
#

and paste the remaining critical + warn, because the permissions issue looks handled now.

So, short version: yes, the auto-fix did its job, but only for the file-permission problems. The remaining security findings are probably policy/config ones.

#

Yep, this is a lot clearer now.

What’s actually left

Hard blocker

  • Telegram group sender allowlist is missing

Hardening warning

  • you still have powerful tools exposed (exec, process, fs edits, elevated, browser) without full sandboxing on a surface that may be reachable by more than one person

Info

  • just a posture summary, not another bug

Smallest clean fix for the critical

#

Add your numeric Telegram user ID as an explicit group sender allowlist:

{
  channels: {
    telegram: {
      allowFrom: ["8734062810"],          // DM auth
      groupAllowFrom: ["8734062810"],     // group sender auth
      groups: {
        "-1001234567890": {
          requireMention: true,
        },
      },
    },
  },
}
#

Important:

  • allowFrom / groupAllowFrom = Telegram user IDs
  • groups = negative Telegram group IDs
  • do not put group IDs into groupAllowFrom

If you want to scope it per group instead of globally:

{
  channels: {
    telegram: {
      groups: {
        "-1001234567890": {
          requireMention: true,
          allowFrom: ["8734062810"],
#
        },
      },
    },
  },
}

That should address the critical cleanly.


Best fix for the warn

Your audit is worried because group-triggered sessions can still reach:

  • exec
#
  • process
  • read, write, edit, apply_patch
  • tools.elevated
  • browser control

If this is really only for you, I’d at least harden it to:

{
  agents: {
    defaults: {
      sandbox: { mode: "all" },
    },
  },
  tools: {
    fs: { workspaceOnly: true },
#
  },
}

That won’t magically make it multi-tenant-safe, but it’s the right next step.

If other people can trigger the bot in those Telegram groups, then honestly the warning is justified, and separate gateways is the better architecture.


After editing

Then do:

#
openclaw security audit

What I’d expect after the Telegram allowlist fix:

  • the critical should disappear
  • the warn may remain until you harden sandbox/filesystem/tool exposure
  • the info summary will still exist, which is fine

If you paste your current channels.telegram block, I can rewrite it into the exact final config with your group IDs.

somber geyser
#

how do I get my current channels.telegram block?

midnight rootBOT
#

Easiest way:

openclaw config get channels.telegram

That should print the current effective channels.telegram block.

If you want just a few specific parts:

openclaw config get channels.telegram.allowFrom
openclaw config get channels.telegram.groupAllowFrom
openclaw config get channels.telegram.groups

If you paste it here, please redact anything sensitive first, especially:

#
  • botToken
  • any secrets / passwords / tokens

If config get says the path is missing, then Telegram may be coming from env-only setup or another included config file, and I can help trace that next.

somber geyser
#

OpenClaw security audit
Summary: 0 critical Β· 1 warn Β· 1 info
Run deeper: openclaw security audit --deep

WARN
security.trust_model.multi_user_heuristic Potential multi-user setup detected (personal-assistant model warning)
Heuristic signals indicate this gateway may be reachable by multiple users:

  • channels.telegram.groupPolicy="allowlist" with configured group targets
    No unguarded runtime/process tools were detected by this heuristic.
    No unguarded runtime/filesystem contexts detected.
    OpenClaw's default security model is personal-assistant (one trusted operator boundary), not hostile multi-tenant isolation on one shared gateway.
    Fix: If users may be mutually untrusted, split trust boundaries (separate gateways + credentials, ideally separate OS users/hosts). If you intentionally run shared-user access, set agents.defaults.sandbox.mode="all", keep tools.fs.workspaceOnly=true, deny runtime/fs/web tools unless required, and keep personal/private identities + credentials off that runtime.

INFO
summary.attack_surface Attack surface summary
groups: open=0, allowlist=2
tools.elevated: enabled
hooks.webhooks: disabled
hooks.internal: enabled
browser control: enabled
trust model: personal assistant (one trusted operator boundary), not hostile multi-tenant on one shared gateway

midnight rootBOT
#

Nice, that’s a much healthier result.

What this means now

  • 0 critical: the actual security misconfigurations are gone
  • 1 warn: still just the trust-model reminder
  • 1 info: just an attack-surface summary

About the remaining WARN

At this point it’s basically saying:

you have Telegram group targets configured, so this could be a multi-user surface

But the important part is:

  • No unguarded runtime/process tools were detected
#
  • No unguarded runtime/filesystem contexts detected

That’s the big improvement.

So unless you’re intentionally letting multiple untrusted people use the same gateway, I would treat this remaining warning as advisory, not β€œstill broken”.

About the INFO

That’s just inventory:

  • groups are allowlisted, not open
  • tools.elevated is enabled
  • browser control is enabled
  • internal hooks are enabled
  • webhooks are disabled

Nothing there is automatically wrong, it just means those surfaces exist.