DIYgod/RSSHub · error · Error
API request failed: ${error}
Error message
API request failed: ${error} What it means
Thrown by the Mercari fetch helper when the underlying ofetch call rejects for any reason — network error, non-2xx HTTP status, TLS failure, or a body-parse error. The helper wraps the original error in a new Error with message 'API request failed: <error>' and attaches the original via { cause }. The <error> is the stringified error object, so it often includes the HTTP response details.
Source
Thrown at lib/routes/mercari/util.tsx:288
const headers = new Headers({
DPOP,
'X-Platform': 'web',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'application/json; charset=utf-8',
});
const options = {
method,
headers,
body: method === 'POST' ? JSON.stringify(data) : undefined,
query: method === 'GET' ? data : undefined,
};
try {
return await ofetch<T>(url, options);
} catch (error) {
throw new Error(`API request failed: ${error}`, { cause: error });
}
};
const pageToPageToken = (page: number): string => {
if (page === 0) {
return '';
}
return `v1:${page}`;
};
interface SearchOptions {
categoryId?: number[];
brandId?: number[];
priceMin?: number;
priceMax?: number;
itemConditionId?: number[];
excludeKeyword?: string;
itemTypes?: string[];View on GitHub (pinned to bed535e087)
Solutions
- Inspect error.cause for the HTTP status code — 401/403 means the DPOP signing flow needs updating, 429 means back off, 5xx means retry later.
- If Mercari changed its API, update generateDPOP and the endpoint URLs in lib/routes/mercari/util.tsx.
- Add retry logic with exponential backoff for transient (5xx, network) failures.
- For geo-blocking, route the request through a Japan-region proxy.
Example fix
// before
try {
return await ofetch<T>(url, options);
} catch (error) {
throw new Error(`API request failed: ${error}`, { cause: error });
}
// after — surface status code, retry transient failures
try {
return await ofetch<T>(url, options);
} catch (error: any) {
const status = error?.response?.status ?? error?.response?.statusCode;
throw new Error(`Mercari API request to ${url} failed (status ${status ?? 'n/a'}): ${error.message ?? error}`, { cause: error });
} Defensive patterns
Strategy: retry
Type guard
function isHttpError(e: unknown): e is { response?: { status?: number; statusCode?: number }; message?: string } {
return typeof e === 'object' && e !== null && 'response' in e;
} Try / catch
async function fetchWithRetry<T>(url: string, data: any, method: 'POST' | 'GET', retries = 2): Promise<T> {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
return await fetchFromMercari<T>(url, data, method);
} catch (error: any) {
const status = error?.response?.status ?? error?.response?.statusCode;
const transient = !status || status >= 500 || status === 429;
if (!transient || attempt === retries) {
throw new Error(`Mercari API failed (status ${status ?? 'n/a'}): ${error.message ?? error}`, { cause: error });
}
await new Promise((r) => setTimeout(r, 500 * 2 ** attempt));
}
}
throw new Error('unreachable');
} Prevention
- Inspect error.cause.response.status to classify the failure (auth, rate-limit, server, network).
- Retry only transient failures (5xx, 429, network) with exponential backoff.
- Keep the DPOP signing keys current — Mercari rotates them.
- For geo-blocked deployments, route requests through a Japan egress.
When it happens
Trigger: Mercari's DPOP/JWT signature is rejected (auth failure → 401/403). Rate limiting (429). Mercari API maintenance or outage (5xx). Network connectivity issues from the RSSHub server. The request URL/query is malformed. Mercari changed its API version or endpoint path.
Common situations: The DPOP key/certificate used for signing is expired or rotated by Mercari. The server's IP is geo-blocked (Mercari is Japan-only). Transient network blips. Mercari deploys a breaking API change and all requests start failing.
Related errors
- Failed to retrieve user settings from MangaDex API.
- Failed to fetch followings data
- 无法获取用户信息
- ${tagResponse.msg}
- 文章列表获取失败,可能是被临时限制了访问,请稍后重试 ${JSON.stringify(resp.data)}
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/d2b001282f7964d4.
Report an issue: GitHub.