yikart/AiToEarn · error · BadRequestException
YouTube API请求失败
Error message
YouTube API请求失败
What it means
The handler's fallback: if error.response is absent (network failure, timeout, DNS error, request never reached Google) or status is 401/403 with no parsable body and no data.error.message, the service throws BadRequestException('YouTube API请求失败'). It's the catch-all meaning 'the call failed for an unclassified reason'.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/youtube/youtube.service.ts:1312
* 处理API错误
* @param error 错误对象
*/
private handleApiError(error: any) {
console.error('YouTube API Error:', error);
if (error.response) {
// API响应错误
const { status, data } = error.response;
if (status === 401) {
throw new BadRequestException('授权已过期,请重新授权');
} else if (status === 403) {
throw new BadRequestException('权限不足,无法执行此操作');
} else if (data && data.error && data.error.message) {
throw new BadRequestException(`YouTube API错误: ${data.error.message}`);
}
}
throw new BadRequestException('YouTube API请求失败');
}
}
View on GitHub (pinned to d3aa8bea5b)
Solutions
- Log the raw error (error.code, error.cause, error.message) — absence of error.response means the request never completed.
- Check outbound network/DNS/proxy access to www.googleapis.com:443 from the server.
- Add timeouts and classify ECONNABORTED/ENOTFOUND/EAI_AGAIN codes distinctly from API errors.
- Ensure the axios error is actually passed to this handler (not swallowed or wrapped elsewhere).
- Implement retry with exponential backoff for transient network codes.
Example fix
// before
console.error('YouTube API Error:', error);
// after
if (!error.response) {
console.error('Network-level failure:', { code: error.code, message: error.message, cause: error.cause });
throw new BadRequestException(`YouTube 网络请求失败: ${error.code ?? 'UNKNOWN'}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
const reachable = await fetch('https://www.googleapis.com/discovery/v1/apis', { signal: AbortSignal.timeout(5000) }).then(r => r.ok).catch(() => false);
if (!reachable) throw new Error('googleapis.com unreachable from this host'); Type guard
function isNetworkError(e: unknown): boolean {
const anyE = e as any;
return !anyE?.response && ['ECONNREFUSED','ETIMEDOUT','ECONNRESET','ENOTFOUND','EAI_AGAIN','ECONNABORTED'].includes(anyE?.code ?? '');
} Try / catch
try {
return await callYouTubeApi();
} catch (e) {
if (isNetworkError(e)) {
await sleep(backoff(attempt)); // retry with exponential backoff up to N times
return callYouTubeApi();
}
throw e;
} Prevention
- Verify server egress to www.googleapis.com:443 (proxy/firewall/region allowlist).
- Set explicit axios timeouts and classify error.code values.
- Retry transient network codes with exponential backoff and jitter.
- Centralize error mapping so unclassified failures log code/cause instead of a bare message.
When it happens
Trigger: error.response is undefined: connection refused/timeout, proxy blocking googleapis.com, ECONNRESET, TLS issues, or offline server; also 401/403 responses whose body lacks error.error.message fall through here.
Common situations: Corporate proxy/firewall blocking outbound HTTPS to www.googleapis.com; server in a region without YouTube API access; DNS misconfiguration; axios misconfiguration (no adapter/timeout); error object not an AxiosError at all.
Related errors
- Failed to fetch image: ${response.status} ${response.statusT
- Relay uploadSign returned no uploadUrl: ${JSON.stringify(sig
- S3DownloadFileFailed
- ResponseCode.S3DownloadFileFailed
- ResponseCode.S3DownloadFileFailed
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/0f067415b5825665.
Report an issue: GitHub.