Search pipeline hangs/crashes with no error response when model output leaks Harmony-format tokens
Summary
/api/search in balanced/quality optimization mode crashes server-side, and (as of a follow-up repro on 2026-09-11) the same failure shape also hangs silently in speed mode for at least one query — when the chat model's raw completion leaks Harmony-style special tokens (<|channel|>...<|tool_call|>) into the text Vane's action-dispatch parser reads.
Environment
- Vane deployed standalone (
itzcrazykns1337/vane:slim-latest), fronted by SearXNG (own instance,braveapiengine) and aPOST /api/providersOpenAI-compatible provider pointed at an internal LLM gateway (Ollama-backed,gemma4:26b, MoE). - Consumed via a custom MCP wrapper (
thetom42/perplexica-mcp) calling Vane's plain/api/searchREST endpoint. - Also reproduced through Open WebUI's native MCP tool-server integration (real browser session, not just direct API calls).
Original crash (balanced/quality mode)
Request body sets optimizationMode: "balanced" (or "quality", or omits optimizationMode — Vane's own server-side default is balanced). Server logs:
Error: Action with name __reasoning_preamble<channel|><|tool_call>call:web_search
not foundThis comes from i.research/k.searchAsync in the compiled app/api/search/route.js action-dispatch code. It's an unhandled exception — the HTTP request never gets a response, no error is returned to the caller, and the connection just hangs until the client's own read-timeout gives up and tears down the session.
Root cause: the chat model's completion contains literal Harmony-format tokens (<|channel|>, <|tool_call|>, etc. — the same token family that broke #1066, though via a different code path) that leak through into the plain-text stream Vane's action parser expects to contain only its own action-tag syntax. The parser has no fallback for unrecognized/malformed action names — it throws, and the throw isn't caught anywhere in the request path.
Workaround found: setting optimizationMode: "speed" explicitly avoids this code path entirely and was verified working end-to-end for the query that originally triggered the crash.
Follow-up: same hang shape reproduced in speed mode (2026-09-11)
Re-tested through a real Open WebUI browser session (Playwright-driven, MCP tool toggled on) with optimizationMode still going through the caller's default (now "speed", since the caller-side workaround was applied) and a different query ("What is today's top headline on Hacker News?"). Observed via docker logs ollama-webui:
POST .../mcp(the tool call to Vane) succeeds —200 OK.- Then total silence: no further chat-completion activity, no error of any kind.
- ~3m21s later, the caller's own read-timeout tears down the MCP session (
DELETE .../mcp,200 OK). - The assistant's message in the UI stays completely empty the entire time.
No corresponding runtime request logging appeared in docker logs/kubectl logs for the Vane container itself in either case — Vane does not appear to log anything at the request level once past startup, which is consistent with #1172/#997 ("errors aren't surfaced/logged").
This means either:
- The
speed-mode workaround doesn't fully avoid the Harmony-token-leak code path for every query, or - This is a distinct silent hang with the same "unhandled promise rejection swallowed somewhere in the request path, connection just never resolves" shape.
Either way, the underlying bug is the same class: Vane's server-side request handling has no top-level error boundary for the search pipeline, so a bad/unexpected model output (or possibly some other transient failure) becomes a permanently-hanging HTTP request instead of a 500 with a message.
Suggested fix
- Wrap the search pipeline (
i.research/k.searchAsyncand whatever handlesspeedmode) in a try/catch that always resolves the HTTP response, even on unexpected internal errors — turn "hangs forever" into "returns 500 with a message," which alone would make this whole class of bug debuggable from the outside (also addresses #1172/#997). - Make the action-dispatch parser tolerant of unrecognized action names/leaked model special-tokens instead of throwing on them — sanitize or strip
<|...|>-style tokens before parsing, or treat an unparseable action as "no action" rather than a hard error.
Reproduction
Available on request — have full timestamped log evidence (docker logs ollama-webui, provider/model config) for both the original crash and the 2026-09-11 follow-up hang.
Source: ItzCrazyKns/Vane