#Why some messages are not delivered to Discord but can be seen in the UI
1 messages · Page 1 of 1 (latest)
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:
- Use a stronger tool-calling model for Discord/channel sessions.
- Or restore legacy auto-posting for group/channel final replies:
{
messages: {
groupChat: {
visibleReplies: "automatic",
},
},
}
Then restart the gateway.
Also worth checking if this happens specifically in threads/forums: make sure the bot has Send Messages in Threads permission.
Docs: https://docs.openclaw.ai/channels/discord and https://docs.openclaw.ai/channels/troubleshooting
I currently have
"messages": {
"ackReactionScope": "all",
"ackReaction": "âś…",
"groupChat": {
"visibleReplies": "message_tool"
}
},
will change and test
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. 🦞
How can I search for all available image models
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]'
Useful docs: https://docs.openclaw.ai/cli/infer and https://docs.openclaw.ai/cli/models 🦞
which are the free available models?
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)"'
why do gemini gemini-3.1-flash-image-preview always timeout or shows 429?
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.
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]
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. 🦞
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
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-2currently rejectsbackground: "transparent"; useopenai/gpt-image-1.5when you need transparent PNG/WebP
For a transparent generation test:
openclaw infer image generate \
--model openai/gpt-image-1.5 \
--output-format png \
--background transparent \
--prompt "simple lobster sticker, transparent background" \
--json
Docs: https://docs.openclaw.ai/tools/image-generation and https://docs.openclaw.ai/gateway/config-agents
Also, if this behaves differently on your machine, paste openclaw --version first so we don’t chase a version mismatch. 🦞
That error usually means one of two things:
- You still have unsupported keys inside it (
resolution,quality,outputFormat,background,count), or - 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. 🦞
how do I check if ollama web search is configured
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 signinon that host - for hosted Ollama search, use
baseUrl: "https://ollama.com"plus a realOLLAMA_API_KEY
{
"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"
]
}
]
}
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.
is there a model other then codex that comes with their own web_search?
Yes — but with a distinction:
Provider-native / “comes with the model call” web search:
- Direct OpenAI Responses models can use OpenAI’s hosted
web_searchautomatically 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:
geminiuses Google Search groundinggrokuses xAI web groundingkimiuses Moonshot/Kimi web search groundingollamauses 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:
openclaw infer web providers --json
I use opencode-go
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
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
]
}
}
},
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
how do I onboard bravesearch?
Quick path:
- Check your version first, just to avoid stale config advice:
openclaw --version
-
Get a Brave Search API key:
https://brave.com/search/api/ -
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: {
search: {
enabled: true,
provider: "brave",
maxResults: 5
},
fetch: { enabled: true }
}
}
}
Then restart/reload the gateway if needed and test with a normal current-info question.
Docs: https://docs.openclaw.ai/tools/brave-search and https://docs.openclaw.ai/tools/web
what is the difference?
mode: "web" // or "llm-context"
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.
do I need to do anything for duckduckgo?
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.
I have duckduckgo, ollama and brave do i just mark
search: {
enabled: true,
then how will openclaw prioritise?
Yep — for fallback behavior, leave provider out:
search: {
enabled: true
}
Then OpenClaw auto-detects in priority order. With your setup, the practical order is:
- Brave — because you have a Brave API key configured
- DuckDuckGo — first key-free fallback
- 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.
what does first key-free fallback means?
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.”
I have brave and ollama configured but it's still using duckduckgo first "maxResults": 10 but that still gives me count: 5
Two separate things are happening here:
- Why DuckDuckGo first?
Ifprovideris 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.
- Why
maxResults: 10still becomescount: 5?
5is the default search count. For Brave,tools.web.search.maxResultsis used only when the tool call does not explicitly passcount. If the agent/tool call sayscount: 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_searchwithcount: 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.
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
}
},
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:
- Because you have
openaiCodex.enabled: true, Codex-capable models can use native Codex/OpenAI web search instead of the managed OpenClawweb_searchprovider. 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 }
- 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.
I just tried openclaw infer web search --query "OpenClaw docs" --json
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-contextmode issue; test withmode: "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