#Why some messages are not delivered to Discord but can be seen in the UI

1 messages · Page 1 of 1 (latest)

clear flume
#

I am using OpenClaw 2026.5.7 and some of the messages are not getting delivered to discord but can be seen in the UI

idle daggerBOT
#

That symptom usually means Discord received/processed the turn, but the agent’s final reply stayed private instead of being posted back to the channel.

In Discord guild/channel sessions, visible replies must be sent with message(action=send). If the selected model sometimes answers as a normal final response, you’ll see it in the UI/session, but Discord won’t get a message.

Fast check:

openclaw logs --follow

Look around the affected turn for didSendViaMessagingTool: false. That’s the giveaway.

Fix options:

  1. Use a stronger tool-calling model for Discord/channel sessions.
  2. Or restore legacy auto-posting for group/channel final replies:
{
  messages: {
clear flume
#

I currently have

"messages": {
"ackReactionScope": "all",
"ackReaction": "âś…",
"groupChat": {
"visibleReplies": "message_tool"
}
},

will change and test

idle daggerBOT
#

Yep — that config explains it.

visibleReplies: "message_tool" means “only post to Discord if the model explicitly calls the message tool.” So if the model occasionally produces a normal final answer instead, it shows in the UI but does not get delivered to Discord.

Change that to:

messages: {
  ackReactionScope: "all",
  ackReaction: "âś…",
  groupChat: {
    visibleReplies: "automatic",
  },
}

Then restart the gateway and test the same kind of prompt again. If it fixes it, that was the issue. 🦞

clear flume
#

How can I search for all available image models

idle daggerBOT
#

There are two slightly different things people mean by “image models”:

Image generation/edit providers/models:

openclaw infer image providers --json

That shows discoverable/configured/selected image providers and the generation/edit capabilities they expose.

Vision/image-input chat models:

openclaw models list --all --json | jq '.models[] | select((.input // []) | index("image")) | "\(.provider)/\(.id)"'

If your JSON shape differs slightly, first inspect it with:

openclaw models list --all --json | jq '.models[0]'
clear flume
#

which are the free available models?

idle daggerBOT
#

The free list changes constantly, so don’t trust a pasted list from me — ask your install/live catalog instead.

For OpenRouter free candidates:

openclaw models scan --no-probe --json

If you have an OpenRouter key and want OpenClaw to actually probe tool/image support:

openclaw models scan --json

For all models your local OpenClaw can currently see:

openclaw models list --all
#

And for vision/image-input models from that list:

openclaw models list --all --json | jq '.models[] | select((.input // []) | index("image")) | "\(.provider)/\(.id)"'

Docs: https://docs.openclaw.ai/cli/models

clear flume
#

why do gemini gemini-3.1-flash-image-preview always timeout or shows 429?

idle daggerBOT
#

Most likely: it’s not an OpenClaw-specific failure — 429 from Gemini means Google rejected the request for quota/rate/capacity reasons, and preview image models are especially bursty/limited.

Common causes:

  • Free/low-tier Gemini quotas are tiny for image generation/preview models.
  • Preview models have lower/stiffer capacity than stable text models.
  • Multiple attempts count too: retries, parallel agent calls, or image probes can burn the limit fast.
  • Timeouts are normal-ish for image generation: it can take longer than the default timeout, especially when the backend is cold or overloaded.

Try a narrow smoke test with a longer timeout:

openclaw infer image generate \
  --model google/gemini-3.1-flash-image-preview \
  --prompt "Minimal flat test image: one blue square on a white background, no text." \
  --timeout-ms 180000 \
  --json
#

And check auth/version/logs:

openclaw --version
openclaw models status --probe-provider google
openclaw infer image providers --json
openclaw logs --tail 100

If the log shows 429, the fix is usually: wait, reduce concurrency, use a paid/higher quota project/key, or switch image provider/model. If it’s only timeout, increase the image timeout in the command or config.

Docs: https://docs.openclaw.ai/cli/infer

clear flume
#

openclaw infer image generate
--model google/gemini-3.1-flash-image-preview
--prompt "Minimal flat test image: one blue square on a white background, no text."
--timeout-ms 180000
--json
20:19:32 [image-generation] candidate failed: google/gemini-3.1-flash-image-preview: Google image generation failed (HTTP 429): You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https:… [code=RESOURCE_EXHAUSTED]
Error: Google image generation failed (HTTP 429): You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https:… [code=RESOURCE_EXHAUSTED]

idle daggerBOT
#

Yep, that confirms it: this is a Google quota/rate-limit rejection, not a timeout and not OpenClaw failing locally.

HTTP 429 + RESOURCE_EXHAUSTED + “You exceeded your current quota” means Google is refusing that model for your current API key/project/billing tier. Increasing --timeout-ms won’t help this one.

What to do:

  • Check the Gemini API quota/usage page for the same Google Cloud project/API key you’re using.
  • Make sure billing is enabled / your plan has quota for that preview image model.
  • Wait for the quota window to reset if you’re on free/low tier.
  • Reduce retries/concurrency if agents are making multiple image attempts.
  • Use a different configured image provider/model meanwhile.

You can verify OpenClaw’s side with:

openclaw infer image providers --json
openclaw models status --probe-provider google
#

But the important bit is: the request reached Google, and Google said quota exhausted. 🦞

clear flume
#

Is this in the right format?
"imageGenerationModel": {
"primary": "openai/gpt-image-2",
"resolution": "4K",
"quality": "high",
"outputFormat": "png",
"background": "transparent",
"count": 4,
"fallbacks": [
"gpt-image-1.5"
]
}

#

Problem:

  • agents.defaults.imageGenerationModel: Invalid input
idle daggerBOT
#

Close, but not quite. agents.defaults.imageGenerationModel only accepts:

{
  agents: {
    defaults: {
      imageGenerationModel: {
        primary: "openai/gpt-image-2",
        fallbacks: ["openai/gpt-image-1.5"],
        timeoutMs: 180_000,
      },
    },
  },
}

So these do not belong inside imageGenerationModel config:

#
resolution
quality
outputFormat
background
count

Those are image_generate / openclaw infer image generate request parameters, not model-selection config.

Also two important gotchas:

  • fallback should be fully qualified: "openai/gpt-image-1.5", not just "gpt-image-1.5"
  • openai/gpt-image-2 currently rejects background: "transparent"; use openai/gpt-image-1.5 when you need transparent PNG/WebP

For a transparent generation test:

openclaw infer image generate \
#

That error usually means one of two things:

  1. You still have unsupported keys inside it (resolution, quality, outputFormat, background, count), or
  2. Your OpenClaw version/config schema is older than the docs I’m checking.

Use the minimal known-good shape first:

{
  agents: {
    defaults: {
      imageGenerationModel: "openai/gpt-image-2",
    },
  },
}

If that works, then try the object form:

#
{
  agents: {
    defaults: {
      imageGenerationModel: {
        primary: "openai/gpt-image-2",
        fallbacks: ["openai/gpt-image-1.5"],
        timeoutMs: 180000,
      },
    },
  },
}

If the object form still says invalid, please paste:

#
openclaw --version

And the surrounding agents.defaults config block with secrets removed. My bet is either extra keys are still present, or you’re on a version where imageGenerationModel only accepts the string form. 🦞

clear flume
#

how do I check if ollama web search is configured

idle daggerBOT
#

Quickest checks:

openclaw infer web providers --json

Look for ollama and whether it’s configured / selected / ready. Then do a real search smoke test:

openclaw infer web search --query "OpenClaw docs" --json

To check the config directly:

openclaw config get tools.web.search.provider
#
openclaw config get models.providers.ollama.baseUrl
openclaw config get plugins.entries.ollama.config.webSearch.baseUrl

For Ollama web search specifically, you want either:

tools: { web: { search: { provider: "ollama" } } }

or no provider pinned, with auto-detect falling through to Ollama.

Requirements:

  • local/self-hosted Ollama must be reachable, usually http://127.0.0.1:11434
  • run ollama signin on that host
  • for hosted Ollama search, use baseUrl: "https://ollama.com" plus a real OLLAMA_API_KEY
clear flume
#

{
"search": [
{
"available": true,
"configured": true,
"selected": false,
"id": "duckduckgo",
"envVars": []
},
{
"available": true,
"configured": false,
"selected": false,
"id": "exa",
"envVars": [
"EXA_API_KEY"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "firecrawl",
"envVars": [
"FIRECRAWL_API_KEY"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "gemini",
"envVars": [
"GEMINI_API_KEY"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "grok",
"envVars": [
"XAI_API_KEY"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "kimi",
"envVars": [
"KIMI_API_KEY",
"MOONSHOT_API_KEY"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "minimax",
"envVars": [
"MINIMAX_CODE_PLAN_KEY",
"MINIMAX_CODING_API_KEY",
"MINIMAX_OAUTH_TOKEN",
"MINIMAX_API_KEY"
]
},
{
"available": true,
"configured": true,
"selected": true,
"id": "ollama",
"envVars": []
},
{
"available": true,
"configured": false,
"selected": false,
"id": "perplexity",
"envVars": [
"PERPLEXITY_API_KEY",
"OPENROUTER_API_KEY"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "searxng",
"envVars": [
"SEARXNG_BASE_URL"
]
},
{
"available": true,
"configured": false,
"selected": false,
"id": "tavily",
"envVars": [
"TAVILY_API_KEY"
]
}
]
}

idle daggerBOT
#

Yep — that output says Ollama web search is configured and selected:

{
  "id": "ollama",
  "available": true,
  "configured": true,
  "selected": true
}

So OpenClaw will use Ollama for web_search.

Now verify the actual runtime path with:

openclaw infer web search --query "OpenClaw docs" --json
#

If that fails, the next things to check are:

ollama signin
ollama ps
openclaw config get models.providers.ollama.baseUrl
openclaw config get plugins.entries.ollama.config.webSearch.baseUrl

For local Ollama, OpenClaw uses the daemon’s /api/experimental/web_search proxy, so the daemon needs to be reachable and signed in.

clear flume
#

is there a model other then codex that comes with their own web_search?

idle daggerBOT
#

Yes — but with a distinction:

Provider-native / “comes with the model call” web search:

  • Direct OpenAI Responses models can use OpenAI’s hosted web_search automatically when OpenClaw web search is enabled and you have no managed provider pinned.
  • OpenAI Codex has its own native web-search config under tools.web.search.openaiCodex.

Search-backed providers in OpenClaw’s managed web_search tool:

  • gemini uses Google Search grounding
  • grok uses xAI web grounding
  • kimi uses Moonshot/Kimi web search grounding
  • ollama uses Ollama Web Search
  • plus Brave, Perplexity, Exa, Tavily, etc.

So if you mean “the model provider itself does the search,” look at OpenAI Responses, Gemini, Grok, Kimi, and Ollama. If you mean “native OpenAI-style hosted tool attached to the model request,” that’s mainly OpenAI Responses and Codex in OpenClaw right now.

To see what your install can use:

clear flume
#

I use opencode-go

idle daggerBOT
#

For opencode-go: no, it doesn’t appear to expose its own provider-native web search in OpenClaw.

So with an opencode-go/... model, you should use OpenClaw’s managed web_search tool provider — like your currently selected ollama, or duckduckgo, brave, gemini, kimi, etc.

Important nuance: even if your model is opencode-go/kimi-k2.6, that does not automatically mean you get Moonshot/Kimi web search grounding. The model is hosted through OpenCode Go; Kimi web search is a separate web_search provider that needs KIMI_API_KEY / MOONSHOT_API_KEY or its plugin config.

Given your earlier output, your setup is fine: opencode-go for the chat model + ollama selected for web search.

You can verify with:

openclaw models list --provider opencode-go
openclaw infer web providers --json
openclaw infer web search --query "latest OpenClaw docs" --json

Docs: https://docs.openclaw.ai/providers/opencode-go and https://docs.openclaw.ai/tools/web

clear flume
#

How can I have a backup for search?
"tools": {
"profile": "coding",
"web": {
"search": {
"provider": "ollama",
"enabled": true,
"openaiCodex": {
"enabled": true,
"mode": "cached",
"contextSize": "high"
}
},
"fetch": {
"enabled": true
}
},
"elevated": {
"enabled": true,
"allowFrom": {
"discord": [
XXXXXX
]
}
}
},

idle daggerBOT
#

For web_search, don’t pin a provider if you want provider fallback.

Right now you have:

provider: "ollama"

That makes Ollama an explicit choice, so OpenClaw won’t fall through to other managed search providers when it fails.

Use auto-detect/fallback instead:

{
  tools: {
    profile: "coding",
    web: {
      search: {
        enabled: true,
#
        // no provider here = auto-detect + fallback candidates
        openaiCodex: {
          enabled: true,
          mode: "cached",
          contextSize: "high"
        }
      },
      fetch: { enabled: true }
    }
  }
}

Then configure one or more providers under plugins.entries.<plugin>.config.webSearch.* or env vars. Example:

#
{
  plugins: {
    entries: {
      brave: { config: { webSearch: { apiKey: "..." } } },
      searxng: { config: { webSearch: { baseUrl: "https://your-searxng.example" } } }
    }
  }
}

Important nuance: there isn’t currently a tools.web.search.fallbacks: [...] list like model fallbacks. Fallback behavior happens when the provider is omitted. If you specifically want “try Ollama first, then X”, I don’t think there’s a config knob for that today — you’d need auto-detect order, or file a feature request: https://github.com/openclaw/openclaw/issues

Docs: https://docs.openclaw.ai/tools/web

clear flume
#

how do I onboard bravesearch?

idle daggerBOT
#

Quick path:

  1. Check your version first, just to avoid stale config advice:
openclaw --version
  1. Get a Brave Search API key:
    https://brave.com/search/api/

  2. Run the web config wizard:

openclaw configure --section web

Choose Brave and paste the API key.

Or configure it manually in ~/.openclaw/openclaw.json:

#
{
  plugins: {
    entries: {
      brave: {
        config: {
          webSearch: {
            apiKey: "YOUR_BRAVE_API_KEY",
            mode: "web" // or "llm-context"
          }
        }
      }
    }
  },
  tools: {
    web: {
clear flume
#

what is the difference?
mode: "web" // or "llm-context"

idle daggerBOT
#

mode: "web" is the normal Brave search endpoint:

  • returns classic search results: title, URL, snippet
  • best default for general web search
  • cheaper/simpler shape, works like most search APIs

mode: "llm-context" uses Brave’s LLM Context endpoint:

  • returns source entries with pre-extracted text/chunks meant for grounding an LLM answer
  • better when you want the agent to synthesize an answer from retrieved context
  • can be heavier/more verbose, and has slightly different parameter support

My recommendation: start with web. Switch to llm-context if you notice the agent needs richer page context from search results instead of just snippets.

Docs: https://docs.openclaw.ai/tools/brave-search

clear flume
#

do I need to do anything for duckduckgo?

idle daggerBOT
#

No API key or account needed for DuckDuckGo.

If you want to explicitly use it:

{
  tools: {
    web: {
      search: {
        enabled: true,
        provider: "duckduckgo"
      }
    }
  }
}

Or run:

#
openclaw configure --section web

and choose duckduckgo.

But if you want it as a backup/fallback, leave provider unset. DuckDuckGo is the first key-free fallback after configured API-key providers.

Caveat: it’s unofficial/HTML-based, so it can break or hit bot challenges. Fine as a backup; I’d use Brave for something reliable.

Docs: https://docs.openclaw.ai/tools/duckduckgo-search

clear flume
#

I have duckduckgo, ollama and brave do i just mark
search: {
enabled: true,
then how will openclaw prioritise?

idle daggerBOT
#

Yep — for fallback behavior, leave provider out:

search: {
  enabled: true
}

Then OpenClaw auto-detects in priority order. With your setup, the practical order is:

  1. Brave — because you have a Brave API key configured
  2. DuckDuckGo — first key-free fallback
  3. Ollama Web Search — after DuckDuckGo, if local Ollama is reachable/signed in

So make sure your Brave key is under the plugin config, e.g.:

#
plugins: {
  entries: {
    brave: {
      config: {
        webSearch: {
          apiKey: "YOUR_BRAVE_API_KEY",
          mode: "web"
        }
      }
    }
  }
},
tools: {
  web: {
    search: {
#
      enabled: true
      // no provider = auto + fallback
    },
    fetch: { enabled: true }
  }
}

If you set provider: "brave" / "duckduckgo" / "ollama", that pins it and removes the nice fallback behavior.

Small gotcha: if you specifically want Ollama before DuckDuckGo, I don’t think there’s a config option for that today. Default key-free order is DuckDuckGo, then Ollama.

clear flume
#

what does first key-free fallback means?

idle daggerBOT
#

It means: if OpenClaw can’t find any configured API-key search provider, it chooses the first provider that works without credentials.

So with provider omitted:

  • If Brave has a valid key → OpenClaw uses Brave first.
  • If no API-key provider is usable → it falls back to a no-key provider.
  • The first no-key provider in OpenClaw’s order is DuckDuckGo.
  • After that comes Ollama Web Search if available/signed in.

So “first key-free fallback” = “the first no-API-key option OpenClaw tries when paid/API-key providers aren’t available.”

clear flume
#

I have brave and ollama configured but it's still using duckduckgo first "maxResults": 10 but that still gives me count: 5

idle daggerBOT
#

Two separate things are happening here:

  1. Why DuckDuckGo first?
    If provider is omitted, OpenClaw should prefer configured API-key providers first. So if it’s choosing DuckDuckGo, Brave probably isn’t being detected as ready.

Check these:

plugins: {
  entries: {
    brave: {
      config: {
        webSearch: {
          apiKey: "YOUR_BRAVE_API_KEY",
          mode: "web"
        }
      }
#
    }
  }
},
tools: {
  web: {
    search: {
      enabled: true
      // no provider here
    }
  }
}

Also make sure you restarted/reloaded the gateway after changing config, and run:

#
openclaw config validate
openclaw status --all

If Brave isn’t detected, the status/config output usually makes it obvious.

  1. Why maxResults: 10 still becomes count: 5?
    5 is the default search count. For Brave, tools.web.search.maxResults is used only when the tool call does not explicitly pass count. If the agent/tool call says count: 5, that explicit value wins.

Also, not every provider currently reads tools.web.search.maxResults the same way. DuckDuckGo/Ollama mostly use the tool call’s count, defaulting to 5.

So the reliable fixes are:

  • Get Brave detection working, or temporarily pin it with provider: "brave" while testing.
  • Ask the agent for 10 results, or call/use web_search with count: 10.

If you paste the tools.web.search + plugins.entries.brave part of your config with the key redacted, I can spot the issue quickly.

clear flume
#

Yes I have

"brave": {
"enabled": true,
"config": {
"webSearch": {
"apiKey": "XXXXXXX",
"mode": "llm-context"
}
}
},

"web": {
"search": {
"enabled": true,
"openaiCodex": {
"enabled": true,
"mode": "cached",
"contextSize": "high"
},
"maxResults": 10
},
"fetch": {
"enabled": true
}
},

idle daggerBOT
#

That shape looks mostly right if the brave block is under plugins.entries:

plugins: {
  entries: {
    brave: {
      enabled: true,
      config: {
        webSearch: {
          apiKey: "XXXXXXX",
          mode: "llm-context"
        }
      }
    }
  }
}
#

Two likely gotchas:

  1. Because you have openaiCodex.enabled: true, Codex-capable models can use native Codex/OpenAI web search instead of the managed OpenClaw web_search provider. That path won’t use Brave/DuckDuckGo/Ollama provider priority the same way.

If you want to test OpenClaw’s managed provider selection, temporarily disable native Codex search:

openaiCodex: { enabled: false }
  1. To confirm Brave itself works, temporarily pin it:
search: {
  enabled: true,
  provider: "brave",
#
  maxResults: 10
}

Then ask for a search. If that fails or still doesn’t use Brave, the key isn’t being resolved or the config path isn’t where OpenClaw expects it.

Also: maxResults: 10 is only the default when the tool call omits count. If the agent explicitly calls web_search({ count: 5 }), that overrides the config default. So for testing, ask: “search the web and return 10 results” — or inspect the tool call for count: 10.

clear flume
#

I just tried openclaw infer web search --query "OpenClaw docs" --json

idle daggerBOT
#

That’s the right test command. The next useful check is:

openclaw infer web providers --json

That should show which providers are available/configured/selected. If search chose DuckDuckGo, the providers output should explain whether Brave is considered configured/ready.

Also try pinning Brave in the infer command if supported by your version/help output:

openclaw infer web search --query "OpenClaw docs" --provider brave --json

If --provider isn’t accepted, temporarily set:

#
provider: "brave"

under tools.web.search, restart/reload, and rerun the same infer command.

If Brave fails when pinned, it’s almost certainly one of:

  • key not actually under plugins.entries.brave.config.webSearch.apiKey
  • gateway/CLI reading a different config file than the one you edited
  • Brave API key/plan issue
  • llm-context mode issue; test with mode: "web" first

For the maxResults part: infer web search may still send/resolve count: 5 unless the command has a count/limit flag. Check:

openclaw infer web search --help