can1357/oh-my-pi · error · SearchProviderError
Jina API returned invalid response: expected an object or ar
Error message
Jina API returned invalid response: expected an object or array
What it means
Thrown by callJinaSearch when a 2xx response body from the Jina search API is neither a JSON array of results nor a JSON object (e.g. null, a string, a number). The provider's contract is that Jina returns either a bare results array or an envelope object with code/data, so anything else is treated as an invalid upstream response with no status code.
Source
Thrown at packages/coding-agent/src/web/search/providers/jina.ts:83
if (site) headers["X-Site"] = site;
headers["X-Respond-With"] = "no-content";
headers["X-Retain-Images"] = "none";
const response = await fetchImpl(requestUrl, {
headers,
signal: withHardTimeout(signal, timeoutMs),
});
if (!response.ok) {
const errorText = await response.text();
const classified = classifyProviderHttpError("jina", response.status, errorText);
if (classified) throw classified;
throw new SearchProviderError("jina", `Jina API error (${response.status}): ${errorText}`, response.status);
}
const payload = (await response.json()) as JinaSearchEnvelope | JinaSearchResponse | null;
if (Array.isArray(payload)) return payload;
if (!payload || typeof payload !== "object") {
throw new SearchProviderError("jina", "Jina API returned invalid response: expected an object or array");
}
if (typeof payload.code === "number" && payload.code !== 200) {
throw new SearchProviderError("jina", `Jina API response reported failure (${payload.code})`, payload.code);
}
if (!Array.isArray(payload.data)) {
throw new SearchProviderError("jina", "Jina API returned invalid response: expected data array");
}
return payload.data as JinaSearchResponse;
}
/** Execute Jina web search. */
export async function searchJina(params: JinaSearchParams): Promise<SearchResponse> {
const numResults = clampNumResults(params.num_results, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);
const keyOrResolver: ApiKey = params.authStorage.resolver("jina", {
sessionId: params.sessionId,
});
const response = await withAuth(
keyOrResolver,View on GitHub (pinned to 9690622007)
Solutions
- Retry the request; a 200-with-junk body is often transient middleware behavior.
- Bypass proxies/interceptors so the raw Jina JSON reaches the client.
- Verify network egress isn't a captive portal or hijacking DNS for s.jina.ai.
- Update the package if Jina changed its response envelope; the parser is updated alongside their API.
Example fix
// before: test stub returning junk
const fetchImpl = async () => new Response(null, { status: 200 });
// after: envelope-shaped stub
const fetchImpl = async () => new Response(JSON.stringify({ code: 200, data: [] }), { status: 200 }); Defensive patterns
Strategy: validation
Type guard
function isJinaResultsPayload(p: unknown): p is { code?: number; data: unknown[] } | unknown[] {
return Array.isArray(p) || (typeof p === 'object' && p !== null && Array.isArray((p as { data?: unknown }).data));
} Try / catch
try {
return await search({ provider: 'jina', query });
} catch (err) {
if (err instanceof SearchProviderError && err.message.includes('invalid response')) {
return await retryWithBackoff(() => search({ provider: 'jina', query }));
}
throw err;
} Prevention
- Do not put rewriting proxies in front of s.jina.ai that can return non-JSON 200 bodies.
- Detect captive portals / DNS hijacking in corporate networks.
- Retry once on invalid-response errors; they are usually transient middleware artifacts.
- Keep the client updated against Jina response-envelope changes.
When it happens
Trigger: response.json() on a 200 response resolves to null, a string, or a number instead of an array or object — e.g. an empty body, an HTML/text interstitial mislabeled as JSON, or a middleman rewriting the payload.
Common situations: Proxy/CDN intercepting the request and returning an empty or HTML 200 response; captive portals; Jina API contract changes; custom fetch implementations returning stubbed bodies in tests.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Jina API error (${response.status}): ${errorText}
- Jina API response reported failure (${payload.code})
- bridge call {name!r}: non-JSON response: {body[:200]!r}
- Anthropic API error (${response.status}): ${errorText}
- Ecosia HTML error (${page.status})
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ac911e155488c01f.
Report an issue: GitHub.