can1357/oh-my-pi · error · CodexNoWebSearchError
Codex returned a completion without running web search (no w
Error message
Codex returned a completion without running web search (no web_search_call event); refusing to treat a non-search answer as a search result
What it means
callCodexSearch tracks whether the stream contained any `web_search_call` (or `response.web_search_call`) event. If Codex completed without ever invoking its built-in web search tool, the answer cannot be trusted as a web search result, so a CodexNoWebSearchError is thrown to advance the provider fallback chain. This guards against treating a model's from-memory answer as a searched answer.
Source
Thrown at packages/coding-agent/src/web/search/providers/codex.ts:655
}
} else if (eventType === "error") {
const { code, message } = extractCodexSseError(rawEvent);
throw new SearchProviderError(
"codex",
`Codex error (${code}): ${message || "Unknown error"}`,
classifyCodexSseErrorStatus(code, message),
);
} else if (eventType === "response.failed") {
const { code, message } = extractCodexSseError(rawEvent);
const detail = code
? `Codex request failed (${code}): ${message || "Request failed"}`
: `Codex request failed: ${message || "Request failed"}`;
throw new SearchProviderError("codex", detail, classifyCodexSseErrorStatus(code, message));
}
}
if (!webSearchInvoked) {
throw new CodexNoWebSearchError();
}
const finalAnswer = answerParts.join("\n\n").trim();
const streamedAnswer = streamedAnswerParts.join("").trim();
// Throw to advance the chain whenever Codex emitted nothing but image
// placeholder prose — including the case where the streamed delta itself
// is the placeholder (the model occasionally streams the same text it
// publishes as the final output_text).
const finalIsPlaceholder = finalAnswer.length > 0 && isImagePlaceholderAnswer(finalAnswer);
const streamedIsPlaceholder = streamedAnswer.length > 0 && isImagePlaceholderAnswer(streamedAnswer);
const hasFinalText = finalAnswer.length > 0 && !finalIsPlaceholder;
const hasStreamedText = streamedAnswer.length > 0 && !streamedIsPlaceholder;
if (!hasFinalText && !hasStreamedText && sources.length === 0) {
throw new SearchProviderError("codex", "Codex returned image-only response", 502);
}
const answer = hasFinalText ? finalAnswer : hasStreamedText ? streamedAnswer : "";
// Fallback: when Codex omits url_citation annotations, scrape markdown linksView on GitHub (pinned to 9690622007)
Solutions
- Verify the endpoint actually supports the built-in web_search tool (custom proxies often strip it) and switch to the official Codex endpoint.
- Make the query explicitly search-oriented or pass search directives so the model invokes the tool.
- Configure a different search provider (Brave, Tavily, Exa, Kagi) that performs server-side searches deterministically.
- Check that the configured PI_CODEX_WEB_SEARCH_MODEL supports the web_search tool.
Example fix
// before baseURL: "https://my-proxy.example.com/v1" // proxy strips web_search tool // after baseURL: "https://chatgpt.com/backend-api/codex" // official endpoint with web_search enabled
Defensive patterns
Strategy: fallback
Validate before calling
// ensure the endpoint supports web_search before routing codex searches there:
if (transport.customEndpoint && !endpointDeclaresWebSearchSupport(transport.baseUrl)) {
throw new Error("Custom endpoint does not advertise web_search support");
} Type guard
function isCodexNoWebSearch(e: unknown): e is CodexNoWebSearchError {
return e instanceof CodexNoWebSearchError;
} Try / catch
try {
return await searchCodex(params);
} catch (e) {
if (isCodexNoWebSearch(e)) return searchBrave(params); // deterministic server-side provider
throw e;
} Prevention
- Prefer the official Codex endpoint; custom proxies commonly strip the web_search tool item.
- Phrase queries so the model is clearly asked to search the web.
- Verify the configured model supports the built-in web_search tool.
When it happens
Trigger: Codex streams a normal completion (response.completed) but never emits a web_search_call output item — e.g. the model chose to answer directly, the web-search tool was stripped by a custom endpoint/proxy, or the backend silently disabled the tool for the account.
Common situations: Custom/third-party Codex-compatible endpoints that drop the `additional_tools` web-search item; models that ignore search directives on vague queries; account tiers where server-side web search is disabled.
Related errors
- Codex request failed (${code}): ${message || "Request failed
- Codex returned image-only response
- No Codex web search model is configured.
- No Codex OAuth credentials found. Login with 'omp /login ope
- Model ${model.id} does not support V2 streaming compaction
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6b29085fa8597c74.
Report an issue: GitHub.