
Here’s the bottom line up front. In February 2026, we covered the problems we ran into enabling xAI’s Grok Search in OpenClaw across two separate posts. Re-verifying everything for this consolidation, we found that both manual patches those posts walked through had already been fixed upstream before we even published them. Worse, all six of our posts cited the wrong GitHub issue as the cause. This piece is both the correction and a from-scratch guide to what you actually need today.
🔍 Overview — What Grok Search Is, and Why This Piece Exists
Grok Search is a tool that lets OpenClaw’s AI agents run real-time web searches using xAI’s Grok models. Until it shipped, OpenClaw only supported the Brave Search API — solid search quality, but Brave’s results lean toward plain search snippets, which left something to be desired for fast-moving news or rapidly-changing information. 2026.2.9 (PR #12419) added Grok as a new search provider, wiring the web_search tool into xAI’s /v1/responses endpoint. Grok’s own strength is real-time awareness, so expectations for it as a search provider were high.
We ran into several problems getting the feature working, and split that story across two posts: a February 13 bugfix diary (debugging-log style) and a February 23 setup guide (a cleaned-up tutorial). Looking at both side by side for this consolidation, the two posts didn’t even agree on how many problems there were.
Some context on the timing: Grok Search wasn’t quite ready to use the moment it shipped. PR #12419 had only just merged, and the window when we were actually working on this (early-to-mid February) was also the window when upstream was actively fixing related bugs. So a good chunk of what we ran into wasn’t really our environment’s fault — it was us hitting the feature in its pre-stabilized state. Once you know that, the story later in this piece — patching a bug we didn’t realize was already fixed — makes a lot more sense.
🐛 The Five Problems We Originally Found
Every one of our earlier posts described “4 problems,” but there were actually five distinct problems, and no single post ever laid out all five in one place. The bugfix diary titled itself “3 bugs” but then said “4 problems (2 code bugs + 2 config errors)” in its intro, filing the npm dual-install issue as an unnumbered “bonus.” The setup guide did the mirror-image thing — it numbered the API-key issue as problem #4, and this time filed npm dual-install as an unnumbered resolution step. The net effect across our own content: the number “4” kept repeating, but it was a different 4 each time. This consolidation lists all five, honestly.
| # | Problem | Category |
|---|---|---|
| 1 | Model set to grok-2 (unsupported for web_search) | Config error |
| 2 | include parameter 400 error | Code bug |
| 3 | Search “succeeds” but always returns “No response” | Code bug |
| 4 | npm dual-install left the gateway running stale code | Operational/deployment issue |
| 5 | XAI_API_KEY commented out in .env | Config error |
🔬 How We Diagnosed It
Carrying over the diagnostic trail from the original bugfix diary. The first error we hit was the model-name problem.
xAI API error (400): {"error": "Model not found: grok-2"}
Fixing the model name to grok-4-1-fast surfaced a different error.
xAI API error (400): {"code":"400","error":"Argument not supported: include"}
This one needed a look at the actual code to trace. Once that error was gone, search results came back empty every time, so we called the xAI API directly with curl to see the raw response shape.
curl -s -X POST https://api.x.ai/v1/responses \
-H "Authorization: Bearer $XAI_API_KEY" \
-d '{"model":"grok-4-1-fast",
"input":[{"role":"user","content":"latest AI news"}],
"tools":[{"type":"web_search"}]}'
What OpenClaw’s code expected and what xAI actually returned were completely different shapes.
| What OpenClaw expected | xAI’s actual response shape |
|---|---|
data.output_text | data.output[0].content[0].text |
We came out of this with four takeaways.
- The PR itself is the source of truth. When a model name or config default is unclear, a GitHub PR’s commit message is often faster and more accurate than the official docs — documentation always lags a step behind the code.
- xAI’s API isn’t OpenAI’s. The
/v1/responsesendpoint returns a nested array structure, which trips up code written assuming OpenAI-compatible parsing. - Direct curl is the fastest way to check. Calling the API directly, bypassing the application layer, immediately tells you whether the problem is in your client code or in the API itself.
- Keep npm global installs to one path. Mixing a sudo install with a user-prefix install makes it easy for a service like systemd to end up pointed at the wrong one.
🔧 What We Did About It, At the Time
These are the manual patches we actually applied back then. The two code patches below (problems 2 and 3) get corrected in the “So Where Does That Leave Us?” section — they’d already been fixed upstream. We’re leaving the original record intact for two reasons: it may still be useful to anyone running an older version from that window, and it keeps our own reasoning process transparent.
Cleaning up the npm dual-install — OpenClaw was installed in two places, /usr/lib/node_modules/openclaw/ and ~/.npm-global/lib/node_modules/openclaw/, and the systemd service was pointed at the latter.
sed -i 's|/home/{username}/.npm-global/lib/node_modules/openclaw/dist/index.js|/usr/lib/node_modules/openclaw/dist/index.js|g' \
~/.config/systemd/user/openclaw-gateway.service
systemctl --user daemon-reload
rm -rf ~/.npm-global/lib/node_modules/openclaw
rm ~/.npm-global/bin/openclaw
Fixing the model name — switched grok-2 to grok-4-1-fast.
python3 -c "
import json
with open('/home/{username}/.openclaw/openclaw.json') as f:
d = json.load(f)
d['tools']['web']['search']['grok']['model'] = 'grok-4-1-fast'
with open('/home/{username}/.openclaw/openclaw.json', 'w') as f:
json.dump(d, f, indent=2)
"
(Temporary fix at the time) Patching the include parameter — edited the built file directly with sed.
sudo sed -i 's/if (params.inlineCitations) body.include = \["inline_citations"\];/\/\/ PATCHED/' \
/usr/lib/node_modules/openclaw/dist/reply-DptDUVRg.js
(Temporary fix at the time) Patching the response parsing — added a fallback path by hand.
sudo sed -i 's|content: data.output_text ?? "No response"|content: (data.output_text ?? data.output?.find(o => o.type === "message")?.content?.find(c => c.type === "output_text")?.text) ?? "No response"|' \
/usr/lib/node_modules/openclaw/dist/reply-DptDUVRg.js
Activating the API key — uncommented the line in .env.
sed -i 's/^#XAI_API_KEY=/XAI_API_KEY=/' ~/.openclaw/.env
include-parameter patch or the response-parsing patch above. Check the “So Where Does That Leave Us?” section below first — the build file path (reply-DptDUVRg.js) that both patches targeted doesn’t even exist in the current architecture.🔄 So Where Does That Leave Us?
This is the most important part of this consolidation. We checked all five problems against the actual GitHub PRs, issues, and current code, one by one.

The most important finding: both code bugs were already fixed before we even published. The real fix for the include-parameter bug was PR #12945, merged February 11, 2026. The response-parsing fix was PR #13049, merged February 10, 2026. Both fixes shipped in v2026.2.12, released February 13, 2026 — the exact same day our KO bugfix diary went live. We wrote “the fix is expected in the next release” in future tense; that release was already out.
include-parameter bug to GitHub Issue #12860. Re-verifying it for this consolidation, that issue is actually about the response-parsing bug (problem #3), not the include-parameter one. The real issue for the include-parameter bug is Issue #12910, and PR #12945, which fixed it, was never cited in any of our prior coverage. This was our own citation error, and we’re stating that plainly.To sum up:
Right then, wrong now
- The include-parameter patch and the response-parsing patch — both already fixed upstream. And the whole approach of hand-editing a build file like
reply-DptDUVRg.jsno longer applies at all, now that the Grok/xAI logic has been fully split out into its ownextensions/xai/plugin. The current code (extractXaiWebSearchContent) walks theoutput[]array looking for atype === "message"block, then walkscontent[]inside that to pull out both the text and any citation annotations. The simple index-based fallback we added at the time could break on any small shift in the response shape; the current approach holds up even when intermediate entries likeweb_search_callare mixed in. - The model name
grok-4-1-fast— still a valid model ID, but no longer the default. The current default isgrok-4.3, and xAI’s current flagship isgrok-4.5, released July 8, 2026. More fundamentally, model selection itself is no longer a documented option forweb_search.
Still valid
- The API-key issue — forgetting to set a key in
.envor your config is a mistake that can happen regardless of architecture changes. The config path has moved, though — updated below. - The npm dual-install risk — hasn’t gone away entirely. Official installer scripts have reduced the risk, but it’s still a documented troubleshooting item.
⚙️ The Setup We’d Recommend Today

The config path itself has changed. The tools.web.search.grok.* path our older posts taught still gets read today, for backward compatibility (resolveXaiToolSearchConfig merges the legacy path with the new plugin config), but it’s not what current onboarding actually produces. The recommended path today is plugins.entries.xai.config.webSearch.*, and xAI OAuth is now the preferred auth path over an API key.
{
"plugins": {
"entries": {
"xai": {
"config": {
"webSearch": {
"apiKey": "xai-...(your-key, if you're not using OAuth)",
"baseUrl": "https://api.x.ai/v1"
}
}
}
}
}
}
web_search config. We’d recommend sticking with the default (grok-4.3). If you want to manage the API key directly, the XAI_API_KEY environment variable path still works too.OAuth vs. API key — what’s the difference — the API-key approach, what this piece originally covered, means putting an issued key string directly into a config file or environment variable. If the key leaks or expires, reissuing and managing it is on you. The OAuth path instead authenticates through your xAI account and issues a token, which cuts down on key-management overhead and allows more fine-grained scope control. That’s why OAuth is the path current onboarding leads with. If you already have an API key set up, there’s no need to switch right away — both paths remain supported.
If you still have an old config file lying around — a tools.web.search.grok.* setup won’t suddenly stop working on the current version. resolveXaiToolSearchConfig merges the legacy path together with the new plugin path when it reads config. That said, all new docs and onboarding flows are written against the new path, so it’s worth migrating while you’re at it.
How npm dual-install is prevented today — using the official installer scripts (install.sh, install-cli.sh) is a lot safer. install-cli.sh installs into a single user-owned path (~/.openclaw) only, structurally ruling out a separate root-owned copy ever existing. install.sh detects an already-running gateway service after install/upgrade and handles restarting it. The exact problem we hit back then — upgrading with sudo npm install -g while the gateway kept running old code from a different path — happened precisely because that post-install reconciliation step didn’t exist yet. That said, PATH conflicts from hand-managing multiple npm global-install locations are still a documented troubleshooting scenario, so the risk hasn’t disappeared entirely.
API key issue — what to check
- Confirm the
XAI_API_KEYline in.envisn’t commented out (#) - Confirm the
apiKeyfield in your config isn’t an empty string - If you’re using OAuth, check first whether it’s working without any separate API key set — it takes priority
How to confirm your current setup is actually correct — the most reliable way, same as before, is to call the API directly with curl. On a healthy response, you should find a type: "message" block inside the output[] array, with actual text in its content[]. If you get an empty response or a 400 error the way we used to, the right first suspect this time isn’t a code bug — it’s authentication (an expired OAuth token, a typo’d API key). The two problems that used to be code bugs are already fixed upstream, as covered above.
🧭 Wrapping Up
This consolidation comes down to two points. First, of the original five problems, the two code bugs were already fixed, and the fixes had shipped before we even published. The line we wrote saying a fix was “coming soon” was already false the day we hit publish. Second, we confirmed that our own citation error (misattributing Issue #12860) repeated across all six of the original posts.
Thinking about why this kept happening, the cause wasn’t carelessness — it was timing. Grok Search was a feature where related PRs merged in rapid succession right after release, and we wrote from a single snapshot without keeping pace with that churn. The issue-number misattribution, though, wasn’t a timing problem — it was a plain citation error, and that’s on us to own. Covering a fast-moving open-source project reminded us that a snapshot from one point in time shouldn’t get treated as “current state” — it needs an “as of this date” label attached to it.
If you’re setting up Grok Search fresh today, the “Setup We’d Recommend Today” section above is all you need. Everything else here stays as a record of how, and why, we got it wrong the first time.
📚 References
- PR #12419 — Grok Search provider added
- Issue #12910 — include-parameter 400 error (the real cause)
- PR #12945 — include-parameter bug fix (merged 2026-02-11)
- Issue #12860 — response-parsing bug (the issue we previously misattributed)
- PR #13049 — response-parsing bug fix (merged 2026-02-10)
- Current xAI plugin source — responses-tool-shared.ts
- Current official Grok Search docs
- Official installer script docs
- xAI’s official announcement — Grok 4.5 (2026-07-08)