can1357/oh-my-pi · warning · SearchProviderError

Codex returned image-only response

Error message

Codex returned image-only response

What it means

After filtering out image-placeholder prose (answers that only contain placeholder text for images instead of real content), if the provider produced no usable final or streamed answer text and collected zero sources, callCodexSearch throws a SearchProviderError with status 502. This indicates the model returned a response consisting only of images/placeholder content, giving the caller nothing to return as a search result.

Source

Thrown at packages/coding-agent/src/web/search/providers/codex.ts:669

		}
	}

	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
	// and bare URLs from the synthesized answer so callers still receive sources.
	if (sources.length === 0 && answer.length > 0) {
		for (const source of extractTextSources(answer)) {
			addSource(sources, source);
		}
	}

	return {
		answer,
		sources,
		model,
		requestId,
		usage,
	};

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry the query — this is often transient model behavior; rephrase to request text-based findings.
  2. Let the provider fallback chain advance by catching SearchProviderError and trying the next provider.
  3. Update to a newer version if the backend changed output shape (placeholder detection may need updating).
  4. Switch to a text-first provider (Brave, Tavily) for queries prone to image-only answers.

Example fix

// before
const res = await searchCodex(params); // throws on image-only
// after
try {
  const res = await searchCodex(params);
} catch (e) {
  if (e instanceof SearchProviderError && e.status === 502) return fallbackProvider(params);
  throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

// nothing to validate pre-call; validate post-hoc before consuming:
function hasUsableResult(r: SearchResponse): boolean {
  return Boolean(r.answer?.trim()) || r.sources.length > 0;
}

Type guard

function isImageOnlyCodexResponse(e: unknown): e is SearchProviderError {
  return e instanceof SearchProviderError && e.provider === "codex" && e.message === "Codex returned image-only response";
}

Try / catch

try {
  const res = await searchCodex(params);
  if (!hasUsableResult(res)) return fallbackProvider(params);
  return res;
} catch (e) {
  if (isImageOnlyCodexResponse(e)) return fallbackProvider(params);
  throw e;
}

Prevention

When it happens

Trigger: The Codex stream completes with web_search_call events but every output_text item (and streamed delta) matches isImagePlaceholderAnswer, and no url_citation annotations or web_search_call sources were collected.

Common situations: Model behavior quirks where the search response is dominated by generated images; backend changes that emit image placeholder prose instead of synthesized text; queries whose results are image-only.

Related errors


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