can1357/oh-my-pi · error · Error
TinyFish Search API returned an unexpected response shape
Error message
TinyFish Search API returned an unexpected response shape
What it means
Thrown inside searchTinyFish when the TinyFish Search API's paginated response lacks a `results` array (searchPage.results is not an Array). This is a plain Error, indicating the API response shape does not match the expected contract, which usually means the API version changed, the request hit a proxy/gateway returning an error body with 200 status, or the key/endpoint is misrouted. The library validates defensively instead of crashing on `results.length` etc.
Source
Thrown at packages/coding-agent/src/web/search/providers/tinyfish.ts:192
const excludeDomains = siteHosts(parsed.excludedSites);
if (includeDomains.length > 0) tinyFishParams.include_domains = includeDomains;
if (excludeDomains.length > 0) tinyFishParams.exclude_domains = excludeDomains;
}
const { location, language } = tinyFishLocale(parsed.lang);
if (location) tinyFishParams.location = location;
if (language) tinyFishParams.language = language;
const keyOrResolver: ApiKey = params.authStorage.resolver("tinyfish", {
sessionId: params.sessionId,
});
const sources = await withAuth(
keyOrResolver,
async key => {
const collected: SearchSource[] = [];
const seenUrls = new Set<string>();
for (let page = 0; page <= MAX_PAGE && collected.length < numResults; page += 1) {
const searchPage = await callTinyFishSearch(key, { ...tinyFishParams, page });
if (!Array.isArray(searchPage.results)) {
throw new Error("TinyFish Search API returned an unexpected response shape");
}
appendTinyFishSources(collected, searchPage.results, seenUrls);
if (searchPage.results.length < pageSize) break;
}
return collected.slice(0, numResults);
},
{
signal: params.signal,
missingKeyMessage:
'TinyFish credentials not found. Set TINYFISH_API_KEY or configure an API key for provider "tinyfish".',
},
);
return {
provider: "tinyfish",
sources,
authMode: "api_key",View on GitHub (pinned to 9690622007)
Solutions
- Log the full raw response body from callTinyFishSearch to see what the API actually returned and why `results` is missing
- Verify TINYFISH_API_KEY is valid and not rate-limited/expired, and re-test with curl against the official TinyFish endpoint
- Remove or correct any custom base URL/proxy for the tinyfish provider so requests hit the official API
- Pin or update the provider integration to the current TinyFish API schema (check for renamed `results` field or envelope like {data:[...]})
- Wrap the loop in retry/fallback to another search provider when this shape error occurs
Example fix
// before (crash on shape mismatch)
if (!Array.isArray(searchPage.results)) {
throw new Error("TinyFish Search API returned an unexpected response shape");
}
// after (tolerate envelope variant + log payload)
const raw = searchPage.results ?? (searchPage as any).data;
if (!Array.isArray(raw)) {
logger.error("TinyFish unexpected response", { body: searchPage });
throw new Error(`TinyFish Search API returned an unexpected response shape: ${JSON.stringify(searchPage).slice(0, 500)}`);
} Defensive patterns
Strategy: validation
Validate before calling
function hasTinyFishResults(res: unknown): res is { results: unknown[] } {
return typeof res === "object" && res !== null && Array.isArray((res as { results?: unknown }).results);
}
// call before consuming: if (!hasTinyFishResults(searchPage)) fallback(); Type guard
const isTinyFishPage = (p: unknown): p is { results: SearchSource[] } =>
typeof p === "object" && p !== null && Array.isArray((p as { results?: unknown }).results); Try / catch
try {
results = await searchTinyFish(params);
} catch (err) {
if (err instanceof Error && err.message.includes("unexpected response shape")) {
results = await fallbackProvider.search(params); // or log + retry
} else throw err;
} Prevention
- Pin/monitor the TinyFish API contract and add a CI smoke test asserting `results` is an array
- Use the official endpoint — avoid proxies/gateways that can rewrite the 200 response body
- Keep TINYFISH_API_KEY valid so you never fall through to fallback endpoints with different schemas
- Log the raw response body once on shape failure for fast diagnosis
When it happens
Trigger: callTinyFishSearch resolves but searchPage.results is undefined/null/not an array — e.g. API returns `{error: ...}` or `{data: [...]}` with HTTP 200, an auth gateway returns HTML/JSON without `results`, or the TinyFish API contract changed.
Common situations: Expired or free-tier key hitting a fallback endpoint that returns a JSON error body with 200; corporate proxy or mock server rewriting responses; TinyFish API schema update (results renamed/moved); pointing at a mirror URL that serves a different schema.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Jina API returned invalid response: expected an object or ar
- OpenAI Files API returned an invalid upload response
- OpenAI Files API upload response has an invalid byte count
- ${provider.label} web search is unavailable. Configure its c
- ${provider.label} returned no renderable search content.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/62aa577f856bebd2.
Report an issue: GitHub.