jackwener/OpenCLI · error · CommandExecutionError
申请抖音上传地址响应缺少必要字段: ${JSON.stringify(payload).slice(0, 500)}
Error message
申请抖音上传地址响应缺少必要字段: ${JSON.stringify(payload).slice(0, 500)} What it means
The ApplyUploadInner call succeeded (HTTP ok, no ResponseMetadata.Error) but the response lacks required upload fields: UploadHost, StoreUri, StoreInfo.Auth, Vid, or SessionKey. The library cannot construct the TOS upload URL or commit key without them, so it fails fast with a truncated payload dump (first 500 chars).
Source
Thrown at clis/douyin/_shared/vod-upload.js:158
const url = `${VOD_UPLOAD_HOST}?${params.toString()}`;
const res = await fetch(url, { headers: computeAws4Headers(url, credentials), signal: AbortSignal.timeout(30000) });
const text = await res.text();
let payload;
try {
payload = JSON.parse(text);
} catch {
throw new CommandExecutionError(`申请抖音上传地址失败,非 JSON 响应: HTTP ${res.status} ${text.slice(0, 300)}`);
}
const error = payload?.ResponseMetadata?.Error;
if (!res.ok || error) {
throw new CommandExecutionError(`申请抖音上传地址失败: HTTP ${res.status} ${JSON.stringify(error ?? payload)}`);
}
const uploadNode = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0];
const storeInfo = uploadNode?.StoreInfos?.[0];
const videoId = payload?.Result?.Vid || uploadNode?.Vid;
const sessionKey = uploadNode?.SessionKey ?? storeInfo?.SessionKey ?? payload?.Result?.SessionKey;
if (!uploadNode?.UploadHost || !storeInfo?.StoreUri || !storeInfo?.Auth || !videoId || !sessionKey) {
throw new CommandExecutionError(`申请抖音上传地址响应缺少必要字段: ${JSON.stringify(payload).slice(0, 500)}`);
}
return {
video_id: videoId,
tos_upload_url: `https://${uploadNode.UploadHost}/${storeInfo.StoreUri}`,
auth: storeInfo.Auth,
session_key: sessionKey,
upload_header: uploadNode.UploadHeader ?? {},
user_id: credentials.user_id ?? '',
};
}
export async function commitVideoUploadInner(uploadInfo, credentials) {
if (!uploadInfo?.session_key) {
throw new CommandExecutionError('抖音上传提交缺少 SessionKey');
}
const params = new URLSearchParams({
Action: 'CommitUploadInner',View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the payload dump in the message to see which fields are missing and where the data actually lives.
- Update the extraction paths in applyVideoUploadInner to match the current response schema if Douyin changed it.
- Verify the account/space still allows inner uploads (empty UploadNodes may indicate a permission/quota problem).
- Retry once — occasionally a degraded response is transient.
- Update the CLI/library if a Douyin API version bump altered the upload address structure.
Example fix
// before const uploadNode = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0]; // after const uploadNode = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0] ?? payload?.Result?.UploadAddress?.UploadNodes?.[0]; // tolerate schema variants
Defensive patterns
Strategy: validation
Validate before calling
function hasUploadAddress(payload) {
const node = payload?.Result?.InnerUploadAddress?.UploadNodes?.[0];
const store = node?.StoreInfos?.[0];
return Boolean(node?.UploadHost && store?.StoreUri && store?.Auth
&& (payload?.Result?.Vid || node?.Vid)
&& (node?.SessionKey ?? store?.SessionKey ?? payload?.Result?.SessionKey));
} Type guard
null
Try / catch
try {
uploadInfo = await applyVideoUploadInner(fileSize, creds);
} catch (e) {
if (/缺少必要字段/.test(e.message)) {
console.error('实际响应:', e.message); // adapt extraction paths to schema drift
}
throw e;
} Prevention
- Snapshot real responses in tests to detect Douyin schema drift early.
- Never proceed to PUT/commit when apply fails — abort the pipeline.
- Check account/space upload quota if UploadNodes comes back empty.
- Keep the CLI updated against Douyin API version changes.
When it happens
Trigger: payload.Result.InnerUploadAddress.UploadNodes is empty or missing StoreInfos[0]; Vid and SessionKey absent from all expected locations — typically schema drift or an empty/degraded success response.
Common situations: Douyin changed the response nesting (renamed InnerUploadAddress/UploadNodes/StoreInfos); zero upload nodes returned because the space/quota is misconfigured; a partially migrated API version returns a new shape.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- 抖音上传授权缺少 AccessKeyID/SecretAccessKey/SessionToken
- ${label} did not include a stable text value.
- 抖音上传提交缺少 SessionKey
- Flomo API returned a memo without slug/id
- Sales Navigator lead row missing name
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ed242765c07e3910.
Report an issue: GitHub.