yikart/AiToEarn · warning · Error
下载失败: ${response.status}
Error message
下载失败: ${response.status} What it means
getVideoComments takes videoId as a route param and accountId as a query param; both must be present or BadRequestException('videoId和accountId是必须的') is thrown. limit and cursor are optional pagination parameters.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/agent/mcp/volcengine/volcengine.utils.ts:161
const urlAuthPrimaryKey = config.ai.volcengine?.urlAuthPrimaryKey
if (!playbackBaseUrl || !urlAuthPrimaryKey) {
logger.warn({ fileName }, 'volcengine 未配置,跳过播放 URL 拼接')
return undefined
}
const normalizedFileName = fileName.startsWith('/') ? fileName : `/${fileName}`
const baseUrl = `${playbackBaseUrl}${normalizedFileName}`
const ts = Math.floor(Date.now() / 1000) + 3600
const playbackUrl = this.genTypeAUrl(baseUrl, urlAuthPrimaryKey, ts)
logger.debug({ playbackUrl, fileName }, '拼接播放 URL')
// 使用 fetch 流式下载并上传
const response = await fetch(playbackUrl)
if (!response.ok || !response.body) {
throw new Error(`下载失败: ${response.status}`)
}
const contentLength = response.headers.get('content-length')
const size = contentLength ? Number.parseInt(contentLength, 10) : 0
logger.debug({ size: `${(size / 1024 / 1024).toFixed(2)} MB` }, '开始流式上传')
const arrayBuffer = await response.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
const result = await assetsService.uploadFromStream(userId, buffer, {
type: assetType,
mimeType: 'video/mp4',
size,
}, subPath)
return assetsService.buildUrl(result.asset.path)
}View on GitHub (pinned to d3aa8bea5b)
Solutions
- Include ?accountId=<id> alongside the videoId path segment.
- Guard against JavaScript interpolation producing empty/'undefined' segments in the URL.
- Store accountId with any video reference used for comment views.
Example fix
// before
await api.get(`/plat/tiktok/video/${videoId}/comments?limit=20`);
// after
await api.get(`/plat/tiktok/video/${videoId}/comments?accountId=${encodeURIComponent(accountId)}&limit=20`); Defensive patterns
Strategy: validation
Validate before calling
if (!videoId || !accountId) throw new Error('videoId和accountId是必须的');
await api.get(`/plat/tiktok/video/${videoId}/comments`, { params: { accountId, limit, cursor } }); Type guard
function canLoadComments(videoId: unknown, accountId: unknown): accountId is string {
return typeof videoId === 'string' && videoId.length > 0 && typeof accountId === 'string' && accountId.length > 0;
} Try / catch
try {
return await api.get(`/plat/tiktok/video/${videoId}/comments`, { params: { accountId, limit, cursor } });
} catch (e) {
if (e.response?.status === 400) return { comments: [], cursor: null };
throw e;
} Prevention
- Include accountId as a query param on every comments request
- Sanitize path segments to avoid 'undefined' string interpolation
- Store accountId with any video reference used in comment views
When it happens
Trigger: GET the comments route (/.../:videoId/comments style) without ?accountId=, or a malformed URL where the videoId path segment is empty so routing still matches but the param is empty.
Common situations: Client builds the comment-view URL from a notification payload that only contains videoId and not the account, or template-string interpolation with an undefined accountId produces the literal string 'undefined' vs being dropped — validate before calling.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Invalid subtitle data: ${z.prettifyError(result.error)}
- Canvas not provided and no vid:// video source found in Trac
- tweetId, userId和accountId是必须的
- No subtitle entries in response
- No response from Gemini
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/9ca6a0e772158ca7.
Report an issue: GitHub.