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 links

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the endpoint actually supports the built-in web_search tool (custom proxies often strip it) and switch to the official Codex endpoint.
  2. Make the query explicitly search-oriented or pass search directives so the model invokes the tool.
  3. Configure a different search provider (Brave, Tavily, Exa, Kagi) that performs server-side searches deterministically.
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/6b29085fa8597c74. Report an issue: GitHub.